Skip to content

Commit e1b6826

Browse files
author
José Valim
authored
Raise on recursive macros (#9111)
Closes #9101.
1 parent 462dc57 commit e1b6826

File tree

3 files changed

+24
-13
lines changed

3 files changed

+24
-13
lines changed

lib/elixir/lib/module/locals_tracker.ex

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,7 @@ defmodule Module.LocalsTracker do
3333
"""
3434
def add_local({_set, bag}, from, to, meta, macro_dispatch?)
3535
when is_tuple(from) and is_tuple(to) and is_boolean(macro_dispatch?) do
36-
if from != to do
37-
put_edge(bag, {:local, from}, {to, get_line(meta), macro_dispatch?})
38-
end
39-
36+
put_edge(bag, {:local, from}, {to, get_line(meta), macro_dispatch?})
4037
:ok
4138
end
4239

@@ -114,16 +111,22 @@ defmodule Module.LocalsTracker do
114111
:lists.usort(undefined)
115112
end
116113

117-
defp undefined_local_error(set, local, macro_dispatch?) do
118-
case :ets.lookup(set, {:def, local}) do
119-
[] ->
120-
:undefined_function
114+
defp undefined_local_error(set, local, true) do
115+
case :ets.member(set, {:def, local}) do
116+
true -> false
117+
false -> :undefined_function
118+
end
119+
end
121120

122-
[{_, kind, _, _, _, _}] when kind in @defmacros and not macro_dispatch? ->
121+
defp undefined_local_error(set, local, false) do
122+
try do
123+
if :ets.lookup_element(set, {:def, local}, 2) in @defmacros do
123124
:incorrect_dispatch
124-
125-
_ ->
125+
else
126126
false
127+
end
128+
catch
129+
_, _ -> :undefined_function
127130
end
128131
end
129132

lib/elixir/src/elixir_locals.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ yank(Tuple, Module) ->
2525
reattach(Tuple, Kind, Module, Function, Neighbours, Meta) ->
2626
if_tracker(Module, fun(Tracker) -> ?tracker:reattach(Tracker, Tuple, Kind, Function, Neighbours, Meta) end).
2727

28-
record_local(Tuple, _Module, Function, _Meta, _IsMacroDispatch)
29-
when Function == nil; Function == Tuple -> ok;
28+
record_local(_Tuple, _Module, nil, _Meta, _IsMacroDispatch) ->
29+
ok;
3030
record_local(Tuple, Module, Function, Meta, IsMacroDispatch) ->
3131
if_tracker(Module, fun(Tracker) -> ?tracker:add_local(Tracker, Function, Tuple, Meta, IsMacroDispatch), ok end).
3232

lib/elixir/test/elixir/kernel/errors_test.exs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,14 @@ defmodule Kernel.ErrorsTest do
738738
defmacrop bar, do: :ok
739739
end
740740
'''
741+
742+
assert_eval_raise CompileError,
743+
"nofile:2: cannot invoke macro bar/1 before its definition",
744+
'''
745+
defmodule Kernel.ErrorsTest.IncorrectMacroDispatch do
746+
defmacro bar(a) when is_atom(a), do: bar([a])
747+
end
748+
'''
741749
end
742750

743751
test "macro captured before its definition" do

0 commit comments

Comments
 (0)