by
clemens
(28.10.2024)
Warnings and errors in Elixir macros with the line number of the macro, not the macro calling site
tl;dr
When you’ve got an error or warning in an Elixir macro, the error message will give you the location of the code that is calling the macro, not the line in the macro itself.
To report the line inside the macro, add a location: :keep
to your quote do
.
I.e., consider this macro:
defmacro foo(a) do
quote do
case unquote(a) do
x -> :single
[] -> :empty
nil -> :not_allowed
end
end
end
The compiler will now happily spit out a warning like this:
warning: this clause cannot match because a previous clause at line 5 always matches
│
5 │ use FooWeb.Plug
│ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
│
└─ lib/some_path/some_controller.ex:5
But this is the callers location, i.e. where you called the macro, and if your macros are long you might not spot that error. Now
add the location: :keep
to the quote do
:
defmacro foo(a) do
quote location: :keep do
case unquote(a) do
x -> :single
[] -> :empty
nil -> :not_allowed
end
end
end
And the error message will change to:
warning: this clause cannot match because a previous clause at line 73 always matches
│
74 │ [] -> :no_id
│ ~~~~~~~~~~~~
│
└─ lib/path_to_macro_module/macro_module.ex:74
Which makes finding the actual error way easier.