Instead of incrementing the version for each variable individually we increment it globally for all variables. This means we can uniquely identify each variable assignment with only the version.
Fixes#9392.
When a local bodiless function is called the generated Erlang code is invalid, this commit checks for bodiless locals during the compilation and raises an error on that avoiding the invalid code.
Currently the callbacks on :elixir_compiler are called before the warnings of unused aliases and imports are emitted, causing the messages to not consumed during the compilation. This commit changes `:elixir_lexical.run/2` to `:elixir_lexical.run/3` splitting the callback in two, one during the execution to evaluate the forms and another to be called after all the warnings are emitted.
Fixes#9440
This fixes an edge case in which the compiler will process an
empty list value (`[]`) as a block with no clauses, which is not
possible.
Here is an example:
with {:ok, value} <- Map.fetch(%{a: 1}, :a) do
value
else
[]
end
With this change, the code above will not compile.
When comparing characters in `elixir_tokenizer`, replace `==` and `/=`
with the more efficient `=:=` and `=/=` operators.
The `=:=` and `=/=` operators are more efficient because they can
only return `true` if the operands have the same type:
1> $* =:= 42.
true
2> $* =:= 42.0.
false
In contrast, the `==` operator can return `true` when comparing
an integer and a float:
3> $* == 42.0.
true
Using `=:=` and `=/=` also gives the Erlang compiler more opportunites
for optimization. For example, when compiling the `is_sigil` macro,
the compiler can combine all eight comparisons into a single `select_val`
instruction instead of emitting eight separate instructions.