Previously, the internal Elixir expansion pass worked directly on
Macro.Env. However, this poised an issue, if we want to track
more information in the pass, we ended up exposing it on
Macro.Env, making it larger, and potentially slowing down
operations such as __ENV__ serialization.
This commit refactors the expansion pass to work with two
structures, the Macro.Env struct and a #elixir_ex{} record.
The Elixir compiler spawns a separate process per file.
When a file has to wait on another module, Elixir tracks
in the compiler that the file is waiting.
However, every time a module is defined, the Elixir compiler
spawns a separate process to compile to .beam, and this
process may expand structs in the typespec. Since this
new process is no longer the original file process, Elixir
was not able to track its waiting time.
This PR address this issue by passing the original file_pid
to the .beam compiler process. Note though that, if we
change typespecs to be compiled in the original file process,
this change is no longer required, but at the moment there are
no plans to make such change.
Closes#11036.
Prior to this commit, compilation would copy the module map
(which is the map with the module definitions, attriubutes,
etc) multiple times. In particular, the module execution
process would pass it to the compiler. Then the module
execution process would send it to the parallel compiler
coordinator, which would pass it to the parallel checker
coordinator and then to each individual parallel checker.
That's four copies, which can be quite expensive since it
has the whole Elixir AST.
This commit makes it so it is copied only once. The map
is assembled inside the compiler process and then copied
to the checker process.
This has yielded good improvements in Elixir's test suite.
Before:
Finished in 27.3 seconds (14.4s on load, 7.0s async, 5.8s sync)
After:
Finished in 22.0 seconds (9.4s on load, 6.7s async, 5.8s sync)
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.
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
* Make Module.open?/1 and family to match their docs.
* Cosmetics.
* Introduced internal not_closing state for modules.
It’s stored in a separate ETS and the last field of #elixir_code_server state to minimize impact.
* Use the same ETS for the state.
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.
Prior to this patch, we would always compute the relative
path to the current working directory (CWD), but this meant
consolidated protocols would always get a full path since
they are always outside of their current working directory.
We address this by also storing the relative path in the
definition.
Closes#9095
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.
Unfortunately it is common to have macros that invokes macros
from other modules, leading to mixed quoted expressions causing
the counters to be mixed.
We would need to scope the counters to the caller.
This reverts commit f04f46c49d.
When the module is being compiled, we use deterministic counters instead
of random ones. This should help with most cases of undeterministic
source code or .beam files.
Closes#7955