Age | Commit message (Collapse) | Author |
|
Consider the following functions:
foo() -> bar(not_a_map).
bar(M) when not is_map_key(a, M) -> ok;
bar(_) -> error.
What will `foo/0` return? It depends. If the module is compiled
with the default compiler options, the return value will be
`ok`. If the module is compiled with the `inline` option,
the return value will be `error`.
The correct value is `error`, because the call to `is_map_key/2`
when the second argument is not a map should fail the entire
guard. That is the way other failing guards BIFs are handled.
For example:
foo() -> bar(not_a_tuple).
bar(T) when not element(1, T) -> ok;
bar(_) -> error.
`foo/0` always returns `error` (whether the code is inlined
or not).
This bug can be fixed by changing the classification of `is_map_key/2`
in the `erl_internal` module. It is now classified as a type test,
which is incorrect because type tests should not fail. Reclassifying
it as a plain guard BIF corrects the bug.
This correction also fixes the internal consistency check
failure which was reported in:
https://bugs.erlang.org/browse/ERL-699
|
|
|
|
This complements the `map_get/2` guard BIF introduced in #1784.
Rationale.
`map_get/2` allows accessing map fields in guards, but it might be
problematic in more complex guard expressions, for example:
foo(X) when map_get(a, X) =:= 1 or is_list(X) -> ...
The `is_list/1` part of the guard could never succeed since the
`map_get/2` guard would fail the whole guard expression. In this
situation, this could be solved by using `;` instead of `or` to separate
the guards, but it is not possible in every case.
To solve this situation, this PR proposes a `is_map_key/2` guard that
allows to check if a map has key inside a guard before trying to access
that key. When combined with `is_map/1` this allows to construct a
purely boolean guard expression testing a value of a key in a map.
Implementation.
Given the use case motivating the introduction of this function, the PR
contains compiler optimisations that produce optimial code for the
following guard expression:
foo(X) when is_map(X) and is_map_key(a, X) and map_get(a, X) =:= 1 -> ok;
foo(_) -> error.
Given all three tests share the failure label, the `is_map_key/2` and
`is_map/2` tests are optimised away.
As with `map_get/2` the `is_map_key/2` BIF is allowed in match specs.
|
|
Rationale
Today all compound data types except for maps can be deconstructed in guards.
For tuples we have `element/2` and for lists `hd/1` and `tl/1`. Maps are
completely opaque to guards. This means matching on maps can't be
abstracted into macros, which is often done with repetitive guards. It
also means that maps have to be always selected whole from ETS tables,
even when only one field would be enough, which creates a potential
efficiency issue.
This PR introduces an `erlang:map_get/2` guard-safe function that allows
extracting a map field in guard. An alternative to this function would be
to introduce the syntax for extracting a value from a map that was planned
in the original EEP: `Map#{Key}`.
Even outside of guards, since this function is a guard-BIF it is more
efficient than using `maps:get/2` (since it does not need to set up the
stack), and more convenient from pattern matching on the map (compare:
`#{key := Value} = Map, Value` to `map_get(key, Map)`).
Performance considerations
A common concern against adding this function is the notion that "guards
have to be fast" and ideally execute in constant time. While there are
some counterexamples (`length/1`), what is more important is the fact
that adding those functions does not change in any way the time
complexity of pattern matching - it's already possible to match on map
fields today directly in patterns - adding this ability to guards will
niether slow down or speed up the execution, it will only make certain
programs more convenient to write.
This first version is very naive and does not perform any optimizations.
|
|
|
|
|
|
Follow the same pattern as pid_to_list
|
|
|
|
Implement as ceil/1 and floor/1 as new guard BIFs (essentially part of
Erlang language). They are guard BIFs because trunc/1 is a guard
BIF. It would be strange to have trunc/1 as a part of the language, but
not ceil/1 and floor/1.
|
|
The sys_pre_expand module used to do a lot more (translate records and
funs, for example), but now it does very little. Most of the code is
an identify transformation of the abstract format.
The identity transformation part of the code must be maintained and
kept correct when new forms are added to the abstract format. That
adds to the maintance burden. It also adds (slightly) to compilation
times. Therefore, we want to eliminate sys_pre_expand, moving all of
its (non-identity) transformations to better places.
As a preliminary first step, move the code that adds the pre-defined
functions (such as module_info/0) to a new function in erl_internal.
|
|
Guard tests (e.g. is_list/1) are listed both in guard_bif/2 and
in new_type_test/2. That is a trap for anyone who wants to add
a new guard test. Let guard_bif/2 call new_type_test/2 so that
new guard tests only have to be added in one place.
While we are it, also sort the clauses in guard_bif/2 and
new_type/2.
|
|
|
|
|
|
|
|
The pre-defined types array(), dict(), digraph(), gb_set(), gb_tree(),
queue(), set(), and tid() have been removed.
|
|
product/_, union/_, range/2 as well as tuple/N (N > 0), map/N (N > 0),
atom/1, integer/1, binary/2, record/_, and 'fun'/_ can now be used as
type names.
|
|
To add a type-testing guard BIF, the following steps are needed:
* The BIF itself is added to bif.tab (note that it should be declared
using "ubif", not "bif"), and its implementation to erl_bif_op.c.
* erl_internal must be modified in 3 places: The type test must be
recognized as guard BIF, as a type test, and it must be auto-imported.
* There must be an instruction that implements the same type test as
the BIF (it will be used in guards). beam_utils:bif_to_test/3 must
be updated to recognize the new guard BIF.
|
|
|
|
A process requesting a system task to be executed in the context of
another process will be notified by a message when the task has
executed. This message will be on the form:
{RequestType, RequestId, Pid, Result}.
A process requesting a system task to be executed can set priority
on the system task. The requester typically set the same priority
on the task as its own process priority, and by this avoiding
priority inversion. A request for execution of a system task is
made by calling the statically linked in NIF
erts_internal:request_system_task(Pid, Prio, Request). This is an
undocumented ERTS internal function that should remain so. It
should *only* be called from BIF implementations.
Currently defined system tasks are:
* garbage_collect
* check_process_code
Further system tasks can and will be implemented in the future.
The erlang:garbage_collect/[1,2] and erlang:check_process_code/[2,3]
BIFs are now implemented using system tasks. Both the
'garbage_collect' and the 'check_process_code' operations perform
or may perform garbage_collections. By doing these via the
system task functionality all garbage collect operations in the
system will be performed solely in the context of the process
being garbage collected. This makes it possible to later implement
functionality for disabling garbage collection of a process over
context switches.
Newly introduced BIFs:
* erlang:garbage_collect/2 - The new second argument is an option
list. Introduced option:
* {async, RequestId} - making it possible for users to issue
asynchronous garbage collect requests.
* erlang:check_process_code/3 - The new third argument is an
option list. Introduced options:
* {async, RequestId} - making it possible for users to issue
asynchronous check process code requests.
* {allow_gc, boolean()} - making it possible to issue requests
that aren't allowed to garbage collect (operation will abort
if gc should be needed).
These options have been introduced as a preparation for
parallelization of check_process_code operations when the
code_server is about to purge a module.
|
|
|
|
Added: binary_to_integer/1,2, integer_to_binary/1,2
|
|
|
|
This BIF solves a problem of float_to_list/1 that doesn't allow
specifying the number of digits after the decimal point when
formatting floats.
float_to_list(Float, Options) -> string()
Float = float()
Options = [Option]
Option = {decimals, Decimals::0..249} |
{scientific, Decimals::0..249} |
compact
Returns a string which corresponds to the text representation of
a `Float` formatted using given options.
When decimals option is specified the returned value will contain
at most `Decimals` number of digits past the decimal point.
When `compact` option is provided the trailing zeros at the end
of the list are truncated (this option is only meaningful together
with the `decimals` option). When `scientific` option is provided,
the float will be formatted using scientific notation with
`Decimals` digits of precision. If `Options` is `[]` the function
behaves like `float_to_list/1`. When using `decimals` option and
the number doesn't fit in the static internal buffer of 256 bytes
the function throws `badarg`.
|
|
|
|
* dev:
Make the check_old_code/1 BIF auto-imported
Deprecate the docbuilder application
Conflicts:
lib/stdlib/src/otp_internal.erl
|
|
check_old_code/1 was documented to be auto-imported, but in fact
was not auto-imported. Since check_process_code/2 and the other
code loading BIFs are now auto-imported, for consistency auto-import
check_old_code/1 too.
|
|
concat_binary/1 was deprecated in R13B04, but already in
the R10B-2 release, the documentation recommends using
list_to_binary/1 instead.
|
|
|
|
|
|
|
|
|
|
Added only a few testcases in compiler:error_SUITE and guard_SUITE
The new behaviour of warnings and errors when overriding autoimported BIF's:
Bifs that were autoimported before R14 are dangerous because old code
using them and overriding them in exports can start behaving
differently. For newly added autoimports this can't happen to the new
code that wants to (or dont want to) use them, why only warnings are
added for the BIFs autoimported after the compilator change. Errors
are issued only for code that could have worked in one way in R13 and
now will behave in a different way.
If overriding autoimport with local function:
- if explicit -compile directive supresses autoimport
-> no message
else
- if called from inside module
- if pre R14 autoimported bif
-> error
else
-> warning
else
-> no message
If overriding autoimport with import directive
- if explicit -compile directive supresses autoimport
-> no message
else (regardless of actual usage)
- if pre R14 autoimported bif
-> error
else
-> warning
Calls of local functions or imports overriding autoimported functions
(either post R14 or by using explicit -compile supressions of
autoimport) always goes to the local function or the imported.
The compileation errors are added to not let code like this silently
and disastrously change its semantic (probably to an infinite loop)
between R13 and R14:
----------
-module(m).
-export([length/1]).
length(X) ->
...
Y = length(Z),
....
----------
The user has to select if he/she wants to call length in 'erlang' explicitly
or if the overriding semantics is desired, in which case the -compile
directive has to be used.
-compile({no_auto_import,[F/A]}). Is added to allow to override the
autoimports so that code gets unanbiguous. The directive will remove
an autoimport even if there is no local function or import overriding,
because any other behaviour would be inconsistent and confusing.
record_info and module_info can never be overridden.
|
|
While binary_to_term/2 was added in R13B04, it wasn't auto-imported. This
conformed to longstanding policy of not changing auto-imports between major
versions. This patch contains changes to auto-import binary_to_term/2 to
coincide with the release of R14.
|
|
* pan/otp_8217_binary:
Add documentation for binary module
Add more tests and make some go easier on small systems
Correct Boyer More and trapping for longest_common_suffix
Add longer timetrap to testcases and add binary to app file
Add guard BIFs binary_part/2,3
Add binary:{encode,decode}_unsigned({1,2}
Add referenced_byte_size/1
Add binary:list_to_bin/1 and binary:copy/1,2
Add bin_to_list/{1,2,3}
Add binary:longest_common_prefix/longest_common_suffix
Add binary:part to erl_bif_binary.c
Move binary module bif's to erl_bif_binary.c
Count reductions for process even when not trapping
Add random compare testcase
Teach BIF's binary:match/matches interrupting/restarting
Teach binary.c the semantics to take longest instead of shortest match
Initial commit of the binary EEP
OTP-8217 Implement EEP31
The module binary from EEP31 (and EEP9) is implemented.
|
|
Add the gc_bif's to the VM.
Add infrastructure for gc_bif's (guard bifs that can gc) with two and.
three arguments in VM (loader and VM).
Add compiler support for gc_bif with three arguments.
Add compiler (and interpreter) support for new guard BIFs.
Add testcases for new guard BIFs in compiler and emulator.
|
|
|