Skip to content

Commit 4fa496c

Browse files
author
José Valim
committed
Ensure defaults and defoverridable work together, closes #6300
This commit changes the private super implementation to have a tuple with the {kind, name} as first argument. Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
1 parent bcd1ca6 commit 4fa496c

File tree

11 files changed

+101
-73
lines changed

11 files changed

+101
-73
lines changed

lib/elixir/lib/exception.ex

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ defmodule Exception do
230230
{_, kind, _, clauses} <- List.keyfind(defs, {function, arity}, 0) do
231231
clauses =
232232
for {meta, ex_args, guards, _block} <- clauses do
233-
scope = :elixir_erl.definition_scope(meta, kind, function, arity, "nofile")
233+
scope = :elixir_erl.definition_scope(meta, kind, "nofile")
234234
{erl_args, scope} =
235235
:elixir_erl_clauses.match(&:elixir_erl_pass.translate_args/2, ex_args, scope)
236236
{args, binding} =
@@ -862,8 +862,7 @@ defmodule UndefinedFunctionError do
862862
end
863863

864864
defp format_fa({_dist, fun, arity}) do
865-
fun = with ":" <> fun <- inspect(fun), do: fun
866-
[" * ", fun, ?/, Integer.to_string(arity), ?\n]
865+
[" * ", Inspect.Function.escape_name(fun), ?/, Integer.to_string(arity), ?\n]
867866
end
868867

869868
defp exports_for(module) do

lib/elixir/lib/module/locals_tracker.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ defmodule Module.LocalsTracker do
166166
end
167167

168168
defp unreachable(reachable, private) do
169-
for {tuple, kind, _, _} <- private,
170-
kind == :defmacrop or not :sets.is_element(tuple, reachable),
169+
for {tuple, _, _, _} <- private,
170+
not :sets.is_element(tuple, reachable),
171171
do: tuple
172172
end
173173

lib/elixir/src/elixir.hrl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
-define(var_context, ?MODULE).
66

77
-record(elixir_erl, {
8-
def=nil, %% a tuple with the current definition {def | ..., name, arity}
8+
def=nil, %% the definition kind (def, defp, etc)
99
context=nil, %% can be match, guards or nil
1010
extra=nil, %% extra information about the context, like pin_guard and map_key
1111
caller=false, %% when true, it means caller was invoked

lib/elixir/src/elixir_def.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ local_for(Module, Name, Arity, Kinds) ->
2222
of
2323
{[{_, Kind, Meta, File, _, _}], Clauses} ->
2424
case (Kinds == all) orelse (lists:member(Kind, Kinds)) of
25-
true -> elixir_erl:definition_to_anonymous(File, Module, Tuple, Kind, Meta,
25+
true -> elixir_erl:definition_to_anonymous(File, Module, Kind, Meta,
2626
[Clause || {_, Clause} <- Clauses]);
2727
false -> false
2828
end;
@@ -212,7 +212,7 @@ unpack_defaults(Kind, Meta, Name, Args, E) ->
212212
unpack_defaults(Kind, Meta, Name, [{'\\\\', DefaultMeta, [Expr, _]} | T] = List, Acc, Clauses) ->
213213
Base = match_defaults(Acc, length(Acc), []),
214214
{Args, Invoke} = extract_defaults(List, length(Base), [], []),
215-
Clause = {Meta, Base ++ Args, [], {super, DefaultMeta, Base ++ Invoke}},
215+
Clause = {Meta, Base ++ Args, [], {super, DefaultMeta, [{Kind, Name} | Base] ++ Invoke}},
216216
unpack_defaults(Kind, Meta, Name, T, [Expr | Acc], [Clause | Clauses]);
217217
unpack_defaults(Kind, Meta, Name, [H | T], Acc, Clauses) ->
218218
unpack_defaults(Kind, Meta, Name, T, [H | Acc], Clauses);

lib/elixir/src/elixir_env.erl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ new() ->
2222
prematch_vars => nil}. %% a set of variables defined before the current match
2323

2424
linify({Line, Env}) ->
25-
Env#{line := Line}.
25+
Env#{line := Line};
26+
linify(#{} = Env) ->
27+
Env.
2628

2729
env_to_scope(#{file := File, context := Context}) ->
2830
#elixir_erl{file=File, context=Context}.

lib/elixir/src/elixir_erl.erl

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
%% Compiler backend to Erlang.
22
-module(elixir_erl).
3-
-export([elixir_to_erl/1, definition_to_anonymous/6, compile/1,
3+
-export([elixir_to_erl/1, definition_to_anonymous/5, compile/1,
44
get_ann/1, remote/4, add_beam_chunks/2, debug_info/4,
5-
definition_scope/5]).
5+
definition_scope/3]).
66
-include("elixir.hrl").
77

88
%% TODO: Remove extra chunk functionality when OTP 20+.
@@ -61,8 +61,8 @@ remote(Ann, Module, Function, Args) when is_atom(Module), is_atom(Function), is_
6161

6262
%% Converts an Elixir definition to an anonymous function.
6363

64-
definition_to_anonymous(File, Module, {Name, Arity}, Kind, Meta, Clauses) ->
65-
ErlClauses = [translate_clause(Kind, Name, Arity, Clause, File) || Clause <- Clauses],
64+
definition_to_anonymous(File, Module, Kind, Meta, Clauses) ->
65+
ErlClauses = [translate_clause(Kind, Clause, File) || Clause <- Clauses],
6666
Fun = {'fun', ?ann(Meta), {clauses, ErlClauses}},
6767
LocalHandler = fun(LocalName, LocalArgs) -> invoke_local(Module, LocalName, LocalArgs) end,
6868
{value, Result, _Binding} = erl_eval:expr(Fun, [], {value, LocalHandler}),
@@ -137,14 +137,14 @@ elixir_to_erl_cons2([], Acc) ->
137137

138138
%% Returns a definition scope for translation.
139139

140-
definition_scope(Meta, Kind, Name, Arity, File) ->
140+
definition_scope(Meta, Kind, File) ->
141141
%% TODO: We only need to do this dance because some
142142
%% warnings are raised in elixir_erl_pass. Once we remove
143143
%% all warnings from the Erlang pass, we can remove the
144144
%% file field from #elixir_erl and clean up the code.
145145
case lists:keyfind(location, 1, Meta) of
146-
{location, {F, _}} -> #elixir_erl{def = {Kind, Name, Arity}, file = F};
147-
false -> #elixir_erl{def = {Kind, Name, Arity}, file = File}
146+
{location, {F, _}} -> #elixir_erl{def=Kind,file=F};
147+
false -> #elixir_erl{def=Kind,file=File}
148148
end.
149149

150150
%% Compilation hook.
@@ -167,9 +167,15 @@ split_definition([{Tuple, def, Meta, Clauses} | T], File, Unreachable,
167167
split_definition(T, File, Unreachable, [Tuple | Def], Defmacro, [{N, A} | Exports],
168168
add_definition(Meta, Function, Functions));
169169

170-
split_definition([{Tuple, defp, Meta, Clauses} | T], File, Unreachable,
170+
split_definition([{Tuple, defmacro, Meta, Clauses} | T], File, Unreachable,
171171
Def, Defmacro, Exports, Functions) ->
172-
Function = translate_definition(defp, Meta, File, Tuple, Clauses),
172+
{_, _, N, A, _} = Function = translate_definition(defmacro, Meta, File, Tuple, Clauses),
173+
split_definition(T, File, Unreachable, Def, [Tuple | Defmacro], [{N, A} | Exports],
174+
add_definition(Meta, Function, Functions));
175+
176+
split_definition([{Tuple, Kind, Meta, Clauses} | T], File, Unreachable,
177+
Def, Defmacro, Exports, Functions) ->
178+
Function = translate_definition(Kind, Meta, File, Tuple, Clauses),
173179
case lists:member(Tuple, Unreachable) of
174180
false ->
175181
split_definition(T, File, Unreachable, Def, Defmacro, Exports,
@@ -178,16 +184,6 @@ split_definition([{Tuple, defp, Meta, Clauses} | T], File, Unreachable,
178184
split_definition(T, File, Unreachable, Def, Defmacro, Exports, Functions)
179185
end;
180186

181-
split_definition([{Tuple, defmacro, Meta, Clauses} | T], File, Unreachable,
182-
Def, Defmacro, Exports, Functions) ->
183-
{_, _, N, A, _} = Function = translate_definition(defmacro, Meta, File, Tuple, Clauses),
184-
split_definition(T, File, Unreachable, Def, [Tuple | Defmacro], [{N, A} | Exports],
185-
add_definition(Meta, Function, Functions));
186-
187-
split_definition([{_, defmacrop, _Meta, _Clauses} | T], File, Unreachable,
188-
Def, Defmacro, Exports, Functions) ->
189-
split_definition(T, File, Unreachable, Def, Defmacro, Exports, Functions);
190-
191187
split_definition([], _File, _Unreachable, Def, Defmacro, Exports, {Head, Tail}) ->
192188
{Def, Defmacro, Exports, Head ++ Tail}.
193189

@@ -206,15 +202,15 @@ add_definition(Meta, Body, {Head, Tail}) ->
206202
end.
207203

208204
translate_definition(Kind, Meta, File, {Name, Arity}, Clauses) ->
209-
ErlClauses = [translate_clause(Kind, Name, Arity, Clause, File) || Clause <- Clauses],
205+
ErlClauses = [translate_clause(Kind, Clause, File) || Clause <- Clauses],
210206

211207
case is_macro(Kind) of
212208
true -> {function, ?ann(Meta), elixir_utils:macro_name(Name), Arity + 1, ErlClauses};
213209
false -> {function, ?ann(Meta), Name, Arity, ErlClauses}
214210
end.
215211

216-
translate_clause(Kind, Name, Arity, {Meta, Args, Guards, Body}, File) ->
217-
S = definition_scope(Meta, Kind, Name, Arity, File),
212+
translate_clause(Kind, {Meta, Args, Guards, Body}, File) ->
213+
S = definition_scope(Meta, Kind, File),
218214

219215
{TClause, TS} = elixir_erl_clauses:clause(Meta,
220216
fun elixir_erl_pass:translate_args/2, Args, Body, Guards, S),

lib/elixir/src/elixir_erl_pass.erl

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,24 @@ translate({'__block__', Meta, Args}, S) when is_list(Args) ->
3838

3939
%% Compilation environment macros
4040

41-
translate({'__CALLER__', Meta, Atom}, S) when is_atom(Atom) ->
42-
{{var, ?ann(Meta), '__CALLER__'}, S#elixir_erl{caller=true}};
41+
translate({'__CALLER__', Meta, Atom}, #elixir_erl{def=Kind}=S) when is_atom(Atom) ->
42+
if
43+
Kind == defmacro; Kind == defmacrop ->
44+
{{var, ?ann(Meta), '__CALLER__'}, S#elixir_erl{caller=true}};
45+
true ->
46+
{{atom, ?ann(Meta), nil}, S}
47+
end;
4348

44-
translate({'super', Meta, Args}, #elixir_erl{def={Kind, Name, _}} = S) ->
49+
translate({'super', Meta, [{Kind,Name}|Args]}, S) ->
4550
%% In the expanded AST, super is used to invoke a function
46-
%% with the same name but possibly different arity.
51+
%% in the current module originated from a default clause
52+
%% or a super call.
4753
{TArgs, SA} = translate_args(Args, S),
4854
Ann = ?ann(Meta),
4955
if
5056
Kind == defmacro; Kind == defmacrop ->
5157
MacroName = elixir_utils:macro_name(Name),
52-
{{call, Ann, {atom, Ann, MacroName}, [{var, Ann, '_@CALLER'} | TArgs]}, SA};
58+
{{call, Ann, {atom, Ann, MacroName}, [{var, Ann, '__CALLER__'} | TArgs]}, SA#elixir_erl{caller=true}};
5359
Kind == def; Kind == defp ->
5460
{{call, Ann, {atom, Ann, Name}, TArgs}, SA}
5561
end;

lib/elixir/src/elixir_expand.erl

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -296,14 +296,9 @@ expand({super, Meta, Args}, #{file := File} = E) when is_list(Args) ->
296296

297297
case length(Args) of
298298
Arity ->
299-
{OName, OArity} = elixir_overridable:super(Meta, File, Module, Function),
299+
{Kind, Name} = elixir_overridable:super(Meta, File, Module, Function),
300300
{EArgs, EA} = expand_args(Args, E),
301-
OArgs =
302-
if
303-
OArity > Arity -> [{'__CALLER__', [], nil} | EArgs];
304-
true -> EArgs
305-
end,
306-
{{OName, Meta, OArgs}, EA};
301+
{{super, Meta, [{Kind, Name} | EArgs]}, EA};
307302
_ ->
308303
form_error(Meta, File, ?MODULE, wrong_number_of_args_for_super)
309304
end;

lib/elixir/src/elixir_overridable.erl

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ overridable(Module, Value) ->
1515

1616
super(Meta, File, Module, Function) ->
1717
case store(Module, Function, true) of
18-
{ok, Name} ->
19-
Name;
18+
{_, _} = KindName ->
19+
KindName;
2020
error ->
2121
elixir_errors:form_error(Meta, File, ?MODULE, {no_super, Module, Function})
2222
end.
2323

2424
store_pending(Module) ->
2525
[begin
26-
{ok, _} = store(Module, Pair, false),
26+
{_, _} = store(Module, Pair, false),
2727
Pair
2828
end || {Pair, {_, _, _, false}} <- maps:to_list(overridable(Module)),
2929
not 'Elixir.Module':'defines?'(Module, Pair)].
@@ -42,7 +42,7 @@ store(Module, Function, Hidden) ->
4242
false ->
4343
{Kind, Name, Arity, Clauses};
4444
true when Kind == defmacro; Kind == defmacrop ->
45-
{defp, name(Name, Count), Arity + 1, rewrite_clauses(Clauses)};
45+
{defmacrop, name(Name, Count), Arity, Clauses};
4646
true ->
4747
{defp, name(Name, Count), Arity, Clauses}
4848
end,
@@ -62,15 +62,11 @@ store(Module, Function, Hidden) ->
6262
ok
6363
end,
6464

65-
{ok, Tuple};
65+
{FinalKind, FinalName};
6666
error ->
6767
error
6868
end.
6969

70-
rewrite_clauses(Clauses) ->
71-
[{Meta, [{'__CALLER__', [], nil} | Args], Guards, Body} ||
72-
{Meta, Args, Guards, Body} <- Clauses].
73-
7470
name(Name, Count) when is_integer(Count) ->
7571
list_to_atom(atom_to_list(Name) ++ " (overridable " ++ integer_to_list(Count) ++ ")").
7672

@@ -83,6 +79,6 @@ format_error({no_super, Module, {Name, Arity}}) ->
8379
[Name, Arity, elixir_aliases:inspect(Module), Joined]).
8480

8581
format_fa({Name, Arity}) ->
86-
A = atom_to_binary(Name, utf8),
82+
A = 'Elixir.Inspect.Function':escape_name(Name),
8783
B = integer_to_binary(Arity),
8884
<<A/binary, $/, B/binary>>.

lib/elixir/test/elixir/kernel/expansion_test.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ defmodule Kernel.ExpansionTest do
170170
end
171171

172172
test "__CALLER__" do
173+
assert __CALLER__ == nil
173174
assert expand(quote do: __CALLER__) == quote do: __CALLER__
174175
end
175176

0 commit comments

Comments
 (0)