__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
And vice-versa.
Overriding a macro as a function (and vice-versa) might produce
undesired effects.
For example, it's not clear if the following code should or
should not raise:
defmodule Foo do
def foo, do: bar()
defmacro bar, do: :ok
defoverridable bar: 0
def bar, do: :ok
end
On top of that, `super` does not currently work for such cases.
This is part of an ongoing effort to forbid overriding macros
with functions and vice-versa. New checks will require the
overridable information to be stored more efficiently.
Elixir's with is expanded into a series of nested cases. For
example, this code:
with {:ok, a} <- fun_a(),
{:ok, b} <- fun_b() do
wa = fun_w(a)
wb = fun_w(b)
else
error -> {:c, error}
end
would be expanded to something similar to this:
case fun_a() do
{:ok, a} ->
case fun_b() do
{:ok, b} ->
wa = fun_w(a)
wb = fun_w(b)
var1 ->
case var1 do
error -> {:c, error}
var2 -> error({with_clause, var2})
end
end
var1 ->
case var1 do
error -> {:c, error}
var2 -> error({with_clause, var2})
end
end
The generated code can be optimized for else clauses that
only contain a single catch-all clause (a variable that would
bind everything). Applying this optimization, the code of the
example above would be:
case fun_a() do
{:ok, a} ->
case fun_b() do
{:ok, b} ->
wa = fun_w(a)
wb = fun_w(b)
error ->
{:c, error}
end
error ->
{:c, error}
end
Binary/bitstring matching allows to dynamically define the
`size` of the binary in certain conditions:
* if the `size` variable is defined prior to the pattern
match:
iex> size = 8
iex> <<a::size(size), rest::binary>> = "hello"
iex> a
104
* if the `size` variable is matched within the same
binary/bitstring match, prior to its use:
iex> <<name_size::size(8), name::binary-size(name_size), _rest::binary>> = <<5, "Frank the Walrus">>
iex> name
"Frank"
Other cases are considered illegal patterns, for example:
{name_size, <<name::binary-size(name_size), _rest::binary>>} = {5, "Frank the Walrus"}
This commit raises a `CompileError: undefined variable ...` for such cases.
Today charlist interpolation is quivalent to calling `String.to_charlist`
on the equivalent string interpolation. It can be more efficient by
leveraging chardata support in the `:unicode` module and encoding as a
list of literal binaries and results of `Kernel.to_string` calls for the
interpolated segments.
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.
- Replace "two element tuples" with "two-element tuples" for every number in 1..10
- Replace "2-element tuples" with "two-element tuples" for every number
- "1-based" with "one-based"
- "0-based" with "zero-based"
Closes#8285.
This warning has to be removed because all of the forms were
unified in v1.7, making case/with/if to behave the same.
That leads to undesired warnings in cases such as:
a = 1
with {:ok, a} <- my_fun(a) do
:ok
end
This speeds up the Elixir compiler from 5-10% as we no
longer do duplicate work on erl_lint and expand_records.
We also avoid the copying of messages by controlling
exactly when the compiler spawns new processes.