-
-
Notifications
You must be signed in to change notification settings - Fork 82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Don't run top-level code in .exs
files
#798
Conversation
d2f7782
to
2618593
Compare
Few TODOs on this:
|
Is |
I considered that. I think it's extremely uncommon for a top-level In the same vein, |
I went ahead and implemented the approach I suggested in the PR to fix incorrect unused/undefined variable warnings. Unfortunately, it makes the code rather more complicated, but I've added some unit tests for the stickier bits that will hopefully also help the next person who works on this understand what's going on. Still very open to other approaches, but I couldn't think of any. |
.exs
files before compilation.exs
files
Re: issue 2, I think the use case that won't work is exceedingly rare, and I'm fine not supporting it. |
@scohen 👍 I'll cross that off the list. The only thing to decide on now is whether to exclude tests. My opinion is that we shouldn't. I think the best argument for excluding them from the ".exs treatment" is that the treatment might be buggy, but:
|
Agree, let's give it a shot. This makes working with scripts possible. |
@zachallaun is this ready to merge? |
621d424
to
7852eff
Compare
Lexical's as-you-type compilation and error reporting works by parsing the AST after a small period of quiescence and then compiling it with
Code.compile_quoted/2
. This runs top-level forms, however, so a.exs
script that performs side-effects when run, e.g. creating or deleting a file, would have them run repeatedly unless you wrap them in adef
inside a module.The goal, then, becomes reporting on as many errors/warnings as possible without running top-level forms.
The current approach here is to chunk all top-level forms into "safe" and "unsafe", where safe forms are only
defmodule/use/import/require/alias
. Safe forms stay at the top level, while unsafe forms are wrapped to prevent their execution. Concretely, this script:would be transformed to this after parsing, but prior to compilation:
Issue 1: Incorrect unused/undefined var warnings
This isn't quite good enough, though. It means that if you, for instance, set some constants in your script at the top, you'd get warnings for any usage below if they're separated by a "safe" form. For instance:
This would result in a warning where
dir
is assigned (unused variable) and an error wheredir
is used (undefined variable).Potential solution: collect vars and references in each chunk of top-level code, replacing unused vars with
_var
. Then, for any later chunks, use those vars to build "stub parameters" in the wrapper def to avoid undefined variable errors.Issue 2: Using top-level var as a module name
The approach above will break this code:
I'm personally okay with this as a "known defect" that perhaps could be tackled later on, though I'm not sure a perfect solution exists.
Things this explicitly doesn't address
Mix.install
, which will require wider changes in order to support. Any usage of deps coming from theMix.install
will show "undefined" warnings. To actually support it, we'd need to consider that file its own project, because install doesn't work inside an existing mix project. I think this will be easier to support when we support multiple workspaces.