Skip to content

Commit 881c2d6

Browse files
authored
Support macros with defoverridable/super (#4848)
1 parent 90543e8 commit 881c2d6

File tree

3 files changed

+48
-14
lines changed

3 files changed

+48
-14
lines changed

lib/elixir/src/elixir_def_overridable.erl

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
% Holds the logic responsible for defining overridable functions and handling super.
22
-module(elixir_def_overridable).
3-
-export([setup/1, overridable/1, overridable/2, name/2, super/2, store_pending/1,
3+
-export([setup/1, overridable/1, overridable/2, kind_and_name/2, super/2, store_pending/1,
44
ensure_defined/4, format_error/1]).
55
-include("elixir.hrl").
66
-define(attr, {elixir, overridable}).
@@ -23,15 +23,21 @@ ensure_defined(Meta, Module, Tuple, S) ->
2323
_ -> elixir_errors:form_error(Meta, S#elixir_scope.file, ?MODULE, {no_super, Module, Tuple})
2424
end.
2525

26-
%% Gets the name based on the function and stored overridables
26+
%% Builds a function name based on how many times the function has been
27+
%% overridden.
2728

28-
name(Module, Function) ->
29-
name(Module, Function, overridable(Module)).
30-
31-
name(_Module, {Name, _} = Function, Overridable) ->
32-
{Count, _, _, _} = maps:get(Function, Overridable),
29+
name({Name, _} = _Function, Count) when is_integer(Count) ->
3330
elixir_utils:atom_concat([Name, " (overridable ", Count, ")"]).
3431

32+
%% Returns the kind (def, defp, and so on) of the given overridable function and
33+
%% its overridable name.
34+
35+
kind_and_name(Module, FunctionOrMacro) ->
36+
Overridable = overridable(Module),
37+
{Count, Clause, _, _} = maps:get(FunctionOrMacro, Overridable),
38+
{{{def, _Function}, Kind, _Line, _File, _Check, _Location, _Defaults}, _Clauses} = Clause,
39+
{Kind, name(FunctionOrMacro, Count)}.
40+
3541
%% Store
3642

3743
store(Module, Function, GenerateName) ->
@@ -44,10 +50,15 @@ store(Module, Function, GenerateName) ->
4450
{{{def, {Name, Arity}}, Kind, Line, File, _Check,
4551
Location, {Defaults, _HasBody, _LastDefaults}}, Clauses} = Clause,
4652

47-
{FinalKind, FinalName} = case GenerateName of
48-
true -> {defp, name(Module, Function, Overridable)};
49-
false -> {Kind, Name}
50-
end,
53+
{FinalKind, FinalName, FinalArity} =
54+
case {GenerateName, Kind} of
55+
{false, _} ->
56+
{Kind, Name, Arity};
57+
{true, K} when K == defmacro; K == defmacrop ->
58+
{defp, elixir_utils:macro_name(name(Function, Count)), Arity + 1};
59+
{true, K} when K == def; K == defp ->
60+
{defp, name(Function, Count), Arity}
61+
end,
5162

5263
case elixir_compiler:get_opt(internal) of
5364
false ->
@@ -56,7 +67,7 @@ store(Module, Function, GenerateName) ->
5667
ok
5768
end,
5869

59-
Def = {function, Line, FinalName, Arity, Clauses},
70+
Def = {function, Line, FinalName, FinalArity, Clauses},
6071
elixir_def:store_each(false, FinalKind, File, Location, Module, Defaults, Def)
6172
end.
6273

lib/elixir/src/elixir_translator.erl

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,15 @@ translate({super, Meta, Args}, S) when is_list(Args) ->
161161
"arguments as the current function")
162162
end,
163163

164-
Super = elixir_def_overridable:name(Module, Function),
165-
{{call, ?ann(Meta), {atom, ?ann(Meta), Super}, TArgs}, TS#elixir_scope{super=true}};
164+
{FinalName, FinalArgs} =
165+
case elixir_def_overridable:kind_and_name(Module, Function) of
166+
{Kind, Name} when Kind == def; Kind == defp ->
167+
{Name, TArgs};
168+
{Kind, Name} when Kind == defmacro; Kind == defmacrop ->
169+
{elixir_utils:macro_name(Name), [{var, ?ann(Meta), '_@CALLER'} | TArgs]}
170+
end,
171+
172+
{{call, ?ann(Meta), {atom, ?ann(Meta), FinalName}, FinalArgs}, TS#elixir_scope{super=true}};
166173

167174
%% Variables
168175

lib/elixir/test/elixir/kernel/overridable_test.exs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,18 @@ defmodule Kernel.Overridable do
9393
def many_clauses(x) do
9494
super(x)
9595
end
96+
97+
## Macros
98+
99+
defmacro overridable_macro(x) do
100+
x + 100
101+
end
102+
103+
defoverridable overridable_macro: 1
104+
105+
defmacro overridable_macro(x) do
106+
super(x) + 1_000
107+
end
96108
end
97109

98110
defmodule Kernel.OverridableTest do
@@ -170,4 +182,8 @@ defmodule Kernel.OverridableTest do
170182
"Overridable functions available are: bar/0"
171183
end
172184
end
185+
186+
test "overridable macros" do
187+
assert Overridable.overridable_macro(1) == 1101
188+
end
173189
end

0 commit comments

Comments
 (0)