Better error message for unknown variables inside macros that haven't been required

65 views
Skip to first unread message

Zach Daniel

unread,
Apr 2, 2024, 2:40:42 PMApr 2
to elixir-lang-core
Hey all!

Something that happens very often to Ash users is forgetting to do something like `require Ash.Query`, and then doing something like this:

```
Ash.Query.filter(Resource, name == "fred")
```

Then, they get an error like `error: undefined variable "name"`

What I'm wondering is if we can detect that they are in the arguments of a macro that exists but has not been required, and add a hint at the end of the message like "There is a macro called `Ash.Query.filter/2`, did you perhaps forget to `require Ash.Query`?

I imagine this would help with folks using Ecto as well.

José Valim

unread,
Apr 2, 2024, 5:33:26 PMApr 2
to elixir-l...@googlegroups.com
Unfortunately this is hard. The simplest way to implement this would be by checking on every remote call if the module is available and if the function is macro, which would considerably slow down the compiler. The reason why we have "require" is exactly so we don't need to pay this price. We could maybe add some sort of tracking back to the compiler, but that would be easier said than done.

One alternative approach we could do is to, instead of failing to compile for an undefined variable, we could warn, make it compile, and raise on said code path at runtime. Then some later pass would find this is a macro and warn, but now we are allowing a program that we are certain to fail, to compile and move forward.

Maybe there are other solutions but I can't think of anything else :(

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/cc96a81e-9126-4a9e-bb3a-9a7cd757986cn%40googlegroups.com.

Zach Daniel

unread,
Apr 2, 2024, 5:36:48 PMApr 2
to elixir-l...@googlegroups.com
Could we potentially do something only in the case that we reach this error? Like if a module fails to compile with an undefined variable error, we could attempt to compile it again with some metadata set that tells the compiler that it should check on remote calls if the module is available and the function is a module? Or do something like “go back up the stack” when an undefined error is received and only check the relevant remote calls at that point?

José Valim

unread,
Apr 2, 2024, 5:40:53 PMApr 2
to elixir-l...@googlegroups.com
We could try that. Please open up an issue so we don't forget about it. :)

Zach Daniel

unread,
Apr 2, 2024, 5:42:12 PMApr 2
to elixir-l...@googlegroups.com
Sounds good! I’ll open one now. I’m also happy to investigate adding this, but will need a nudge as to where to start looking. Not high priority, but I think will be a great quality of life improvement for users.

José Valim

unread,
Apr 2, 2024, 6:13:24 PMApr 2
to elixir-l...@googlegroups.com
We have a record that controls compilation:


 You are going to add a new field called "debug". This field can have three values:

* enabled
* disabled
* pending

Whenever we raise because of an undefined variable, we will set the debug mode to pending (if it is disabled).

Now, when compiling a function, we will see if it returns debug as "pending":


If pending, you will set "debug" to enabled and expand it again. The enabled debug mode will disable the variables from raising again and change elixir_dispatch to code:ensure_loaded modules when looking for remote functions, in an attempt to find pending macros.

Reply all
Reply to author
Forward
0 new messages