Age | Commit message (Collapse) | Author |
|
|
|
|
|
|
|
* bjorn/stdlib/function-macro/OTP-13059:
Implement ?FUNCTION_NAME and ?FUNCTION_ARITY macros
epp: Refactor expand_macros()
|
|
* bjorn/remove-test_server/OTP-12705:
Remove test_server as a standalone application
Erlang mode for Emacs: Include ct.hrl instead test_server.hrl
Remove out-commented references to the test_server applications
Makefiles: Remove test_server from include path and code path
Eliminate use of test_server.hrl and test_server_line.hrl
|
|
For a long time, users have asked for one or more macros that would
return the name and arity of the current function.
We could define a single ?FUNCTION macro that would return
a {Name,Arity} tuple. However, to access just the name or
just the arity for the function, element/2 must be used.
That would limit its usefulness, because element/2 is not
allowed in all contexts.
Therefore, it seems that we will need two macros.
?FUNCTION_NAME that expands to the name of the current function
and ?FUNCTION_ARITY that expands to arity of the current
function.
Converting the function name to a string can be done like this:
f() ->
atom_to_list(?FUNCTION_NAME) ++ "/" ++
integer_to_list(?FUNCTION_ARITY).
f/0 will return "f/0". The BEAM compiler will evaluate the
entire expression at compile-time, so there will not be
any run-time penalty for the function calls.
The implementation is non-trivial because the preprocessor is
run before the parser.
One way to implement the macros would be to replace them with some
placeholder and then let the parser or possibly a later pass replace
the placeholder with correct value. That could potentially slow
down the compiler and cause incompatibilities for parse transforms.
Another way is to let the preprocessor do the whole job. That means
that the preprocessor will have to scan the function head to find
out the name and arity. The scanning of the function head can be
delayed until the first occurrence of a ?FUNCTION_NAME or
?FUNCTION_ARITY.
I have chosen the second way because it seems less likely to cause
weird compatibility problems.
|
|
|
|
|
|
|
|
Problem: The types of record fields have since R12B been put in a
separate form by epp:parse_file(), leaving the record declaration form
untyped. The separate form, however, does not follow the syntax of
type declarations, and parse transforms inspecting -type() attributes
need to know about the special syntax. Since the compiler stores the
return value of epp:parse_file() as debug information in the abstract
code chunk ("Abst" or 'abstract_code'), tools too need to know about
the special syntax, if they inspect -type() attributes in abstract
code.
Solution: As of this commit no separate form is created by
epp:parse_file(), but the type information kept in the record fields.
This means that all parse transforms and all tools inspecting
-record() declarations need to recognize {typed_record_field, Field,
Type}.
We recommend that all parse transforms and tools be updated as to
recognize typed record fields.
Discussion: As of OTP 19.0, the abstract form of type declarations and
function specifications is documented. An (unsatisfactory) alternative
to the above solution is to document two formats of the abstract form
of typed record fields: one if returned by epp:parse_file(); and one
if returned by, for example, epp:parse_erl_form(). Yet another (bad)
alternative is to not document the format returned by epp:erl_parse(),
but instead document the idempotent function
epp:restore_typed_record_fields/1, and urge authors of parse transform
and tools to always call this function.
|
|
Since no test suites includede test_server.hrl, there is no need
to have test_server in the include path or code path.
|
|
As a first step to removing the test_server application as
as its own separate application, change the inclusion of
test_server.hrl to an inclusion of ct.hrl and remove the
inclusion of test_server_line.hrl.
|
|
* bjorn/cuddle-with-tests:
erl_prim_loader_SUITE: Refactor helper functions
Move record compilation errors to erl_lint_SUITE
compile_SUITE: Use get_files/3 in more places
compile_SUITE: Replace confusing files/2 with get_files/3
|
|
Conflicts:
lib/stdlib/src/supervisor.erl
|
|
* nybek/speed_up_supervisor_count_children:
Speed up supervisor:count_children/1; simple_one_for_one
Add supervisor:get_callback_module/1
OTP-13290
|
|
The two bad record usage test cases in compile_SUITE do not
belong there, as the errors are detected in erl_lint. Move the
test to the erl_lint_SUITE.
|
|
Speed up supervisor:count_children/1 for simple_one_for_one
supervisors. This is achieved by avoiding looping through all the
child process and verifying that each one is alive.
For a supervisor with 100,000 'temporary' children the count-time will
drop from approx 25ms to about 0.005ms.
For a supervisor with 100,000 'permanent' or 'transient' children the
count-time will drop from approx 30ms to about 0.005ms.
This avoids having the supervisor block for an extended period while
the count takes place. Under normal circumstances the accuracy of the
result should also improve since the duration is too short for many
processes to die during the count.
|
|
* maint:
Introduce time management in native APIs
Introduce time warp safe replacement for safe_fixed option
Introduce time warp safe trace timestamp formats
Conflicts:
erts/emulator/beam/erl_bif_trace.c
erts/emulator/beam/erl_driver.h
erts/emulator/beam/erl_nif.h
erts/emulator/beam/erl_trace.c
erts/preloaded/ebin/erlang.beam
|
|
* rickard/monotonic-time-improvements/OTP-13222:
Introduce time management in native APIs
Introduce time warp safe replacement for safe_fixed option
Introduce time warp safe trace timestamp formats
|
|
The Dets server pretends the file is open before internal_open()
has been called, which means that unless the internal_open
message is applied first, other processes can find the pid by
calling dets_server:get_pid() and do things before Head has been
initialized properly.
|
|
The new time warp safe option is safe_fixed_monotonic_time which
gives erlang:monotonic_time().
The safe_fixed option was also slightly changed. It now gives
erlang:timestamp() instead of erlang:now(). This has however
not been documented, so it is considered a compatible change.
The above effects both ets, and dets.
This commit also include the bugfix OTP-13239 for
dets:info(Tab, safe_fixed). The timestamp in the result returned
by dets:info(Tab, safe_fixed) was unintentionally broken as a
result of the time API rewrites in OTP 18.0.
|
|
See also ERL-55.
|
|
* maint:
stdlib: Fix linter crash due to missing -module declaration
Conflicts:
lib/stdlib/test/erl_lint_SUITE.erl
|
|
The Erlang Code Linter no longer crashes if there is a -deprecated()
attribute but no -module() declaration.
See also ERL-62 at bugs.erlang.org.
|
|
* maint:
stdlib: fix erl_eval not using non-local function handler
|
|
See also ERL-32 at bugs.erlang.org. Thanks to Ben Paxton.
|
|
|
|
* josevalim/jv-map-fun-eval-maint:
Use full list of bindings when matching on map keys
OTP-13218
|
|
|
|
The syntax -spec/callback F/A :: FunctionType; has been removed.
No deprecation was deemed necessary.
|
|
|
|
* maint:
Correct rand:export_seed/0 when there is no prior seed
|
|
* bjorn/stdlib/rand-export_seed/OTP-13162:
Correct rand:export_seed/0 when there is no prior seed
|
|
According to the documentation, rand:export_seed/0 should return
'undefined' if the seed has not been intialized. However, it will
create and return a seed. That means that the following code
will not work as expected:
case rand:export_seed() of
undefined -> rand:seen({1,2,3});
_ -> ok
end,
rand:uniform(Range)
|
|
* maint:
doc: Fix some minor issues in Types and Function Specifications
erts: Remove CDATA from The Abstract Format document
erts: Correct the types section in The Abstract Format document
stdlib: Correct pretty-printing of map types
stdlib: Pretty-print constraints as 'V :: T'
Conflicts:
erts/doc/src/absform.xml
|
|
Add parentheses around annotated type union elements in map pair
types. The bug was introduced in Erlang/OTP 18.0.
|
|
* maint:
Extend erl_lint:format_error/1 to handle bittype mismatches
erl_lint_SUITE: Add smoke test of format_error/1
|
|
erl_lint:format_error/1 would crash with a function error if
conflicting types were given. That was most easily noticed in the
shell:
Eshell V7.0.3 (abort with ^G)
1> <<0/integer-binary>>.
*** ERROR: Shell process terminated! ***
Noticed-by: Aleksei Magusev
|
|
The test suite depended on the compiler to call
erl_lint:format_error/1 to ensure that format_error/1 was
covered. Unfortunately, though, if format_error/1 crashed
the compiler would catch the exception so that the test suite
would not notice it.
Add a smoke test of format_error/1 that will crash if there is
any problem with erl_lint:format_error/1.
|
|
This type modifier was missed in 90efeaf21147505b1e8207822e606027f94183cc.
|
|
* bjorn/cleanup:
epp: Only flatten the original filename
epp: Modernize the internal data structures
epp: Eliminate the Type argument from expand_macros/5
epp: Refactor user_predef/2 to share more code
epp: Refactor scan_define()
epp: Remove vestigial support for packages
epp_SUITE: Improve coverage of epp
epp_SUITE: Extend smoke and cover test of format_error/1
epp_SUITE: Add test of -extends()
|
|
Refactor scan_define() in order to share more between macros
without any arguments and macros with arguments.
|
|
|
|
30a4adb7 added smoke and cover test of format_error/1, but did not
catch calls that went through check/2.
|
|
|
|
Bug introduced om master branch at b93e9b611056828a
and reported in ERL-43.
|
|
|
|
|
|
Prior to this patch, the following code would not eval:
X = key,
(fun(#{X := value}) -> true end)(#{X => value})
That's because the key evaluation was using the new
list of bindings introduced on every anonymous fun.
Since keys only match on values defined prior to the
pattern and do not introduce any new binding, we must
use the full and original list of binding.
|
|
Background
-----------
In record fields with a type declaration but without an initializer, the
Erlang parser inserted automatically the singleton type 'undefined' to
the list of declared types, if that value was not present there.
I.e. the record declaration:
-record(rec, {f1 :: float(),
f2 = 42 :: integer(),
f3 :: some_mod:some_typ()}).
was translated by the parser to:
-record(rec, {f1 :: float() | 'undefined',
f2 = 42 :: integer(),
f3 :: some_mod:some_typ() | 'undefined'}).
The rationale for this was that creation of a "dummy" #rec{} record
should not result in a warning from dialyzer that e.g. the implicit
initialization of the #rec.f1 field violates its type declaration.
Problems
---------
This seemingly innocent action has some unforeseen consequences.
For starters, there is no way for programmers to declare that e.g. only
floats make sense for the f1 field of #rec{} records when there is no
`obvious' default initializer for this field. (This also affects tools
like PropEr that use these declarations produced by the Erlang parser to
generate random instances of records for testing purposes.)
It also means that dialyzer does not warn if e.g. an is_atom/1 test or
something more exotic like an atom_to_list/1 call is performed on the
value of the f1 field.
Similarly, there is no way to extend dialyzer to warn if it finds record
constructions where f1 is not initialized to some float.
Last but not least, it is semantically problematic when the type of the
field is an opaque type: creating a union of an opaque and a structured
type is very problematic for analysis because it fundamentally breaks
the opacity of the term at that point.
Change
-------
To solve these problems the parser will not automatically insert the
'undefined' value anymore; instead the user has the option to choose the
places where this value makes sense (for the field) and where it does
not and insert the | 'undefined' there manually.
Consequences of this change
----------------------------
This change means that dialyzer will issue a warning for all places
where records with uninitialized fields are created and those fields have
a declared type that is incompatible with 'undefined' (e.g. float()).
This warning can be suppressed easily by adding | 'undefined' to the
type of this field. This also adds documentation that the user really
intends to create records where this field is uninitialized.
|