This feature allows IDEs and other tools wanting to
perform source code analysis to do so reliably without
a need to reimplement Elixir's compiler expansion and
without relying on Elixir's private APIs.
This commit also adds :parser_options to compiler
options, which allows developers to combine both options
to retrieve more accurate information, such as columns.
This is important when you may want to check if a module
is available but if that module is running a similar check
on you, you don't want the compiler to fail.
This change fixes inconsistencies when building structs: if the
struct was built using the map syntax the `:__struct__` key
was overridden by the given module name; however, if the struct
was built using `struct/1,2` the `:__struct__` key was kept.
For example:
defmodule X do
defstruct [:x]
end
defmodule Y do
defdelegate __struct__, to: X
defdelegate __struct__(args), to: X
end
iex> %Y{}
%Y{x: nil}
iex> struct(Y)
%X{x: nil}
Closes#8800
__struct__/0,1 is not meant to return an AST. Using
Macro.to_string/1 might lead to incorrect error messages:
defmodule MyStruct do
def __struct__, do: {:ok, :one, :two}
def __struct__(_), do: {:ok, :one, :two}
end
iex> %MyStruct{}
** (CompileError) iex:2: expected MyStruct.__struct__/1 to
return a map with a :__struct__ key that holds the name
of the struct (atom), got: ok
Prior to this patch, if a module depends on the struct of
another module and that other module depends on the struct
of the first module inside typespecs, it would lead to a
compiler deadlock, which this deadlock would not happen
in "regular code".
This commit also adds a test to ensure @enforce_keys are
not enforced when expanding typespecs.
For now, we are using a compiler private API, but we should
provide a public version for it in a future commit.
Optimizes :maps.put/3 to a VM operation instead of a remote call, including nested calls to it.
It does the same for :maps.merge/2 with a simple map on the right side.
Closes#7353
We use this option in ExUnit as we are escaping
the code to eventually convert it to a string
representation and therefore the metadata is not
relevant.
This is a first step to limiting recompilations in case a struct is used in a
module, the "parent module" of the struct changes, but struct definition itself
does not change.
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
Until now, "%x{__struct__: y}" would ignore the ":__struct__" part and only
use/match on "x", without warnings. With this commit, a warning is emitted in
this case and in the respective case when updating ("%SomeStruct{x | __struct__:
y}").
Fixes [issue 5602](https://github.com/elixir-lang/elixir/issues/5602)
Erlang does not accept map_field_exact tag for map used as map keys
since it does not perform any matching on map keys.
For example this fails:
$ erl
Erlang/OTP 19 [erts-8.2] [source-a2c5a92] [64-bit] [smp:8:8]
[async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.2 (abort with ^G)
1> #{ #{1 => X} := 3 } = #{ #{1 => 2} => 3 }.
* 1: illegal map key in pattern
Change how we mark the generated AST for suppressing dialyzer errors -
instead of [generated: true, location: 0], we provide proper line number.
This means, however, that on OTP 18, those nodes won't be recognized
as generated and warnings will be issued.
It was decided that proper error messages are more important than
avoiding bogus dialyzer warnings.
The old mark for generated code is left in places that made compiler
issue warnings on 18.
The bad remote call dialyzer warnings can be suppressed with the
@dialyzer :no_fail_call
module attribute.
With changes to OTP 19, dialyzer started emitting warnings for
the struct update syntax where variable could only be that struct.
For example:
def foo(%Foo{} = struct), do: %Foo{struct | bar: :baz}