Skip to content

Commit ca0250a

Browse files
author
José Valim
committed
Refactor find_dispatch to loop data functions and macros lists just once
1 parent a576540 commit ca0250a

File tree

3 files changed

+59
-60
lines changed

3 files changed

+59
-60
lines changed

lib/elixir/lib/macro.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ defmodule Macro do
563563
end
564564

565565
expand = :elixir_dispatch.expand_import(line, { atom, length(args) }, args,
566-
env.module, env.function, env.requires, extra ++ env.macros, env.functions, env)
566+
env.module, env.function, env.requires, env.functions, extra ++ env.macros, env)
567567
case expand do
568568
{ :ok, _, expanded } -> expanded
569569
{ :error, _ } -> original

lib/elixir/src/elixir_dispatch.erl

Lines changed: 57 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -22,28 +22,25 @@ default_requires() ->
2222

2323
find_import(Meta, Name, Arity, S) ->
2424
Tuple = { Name, Arity },
25-
case find_dispatch(Meta, S#elixir_scope.file, Tuple, S#elixir_scope.functions, S#elixir_scope.macros) of
26-
false ->
27-
case find_dispatch(Meta, S#elixir_scope.file, Tuple, S#elixir_scope.macros, S#elixir_scope.functions) of
28-
false -> false;
29-
Receiver -> Receiver
30-
end;
31-
Receiver -> Receiver
25+
26+
case find_dispatch(Meta, Tuple, S#elixir_scope.functions, S#elixir_scope.macros, S#elixir_scope.file) of
27+
{ function, Receiver } -> Receiver;
28+
{ macro, Receiver } -> Receiver;
29+
nomatch -> false
3230
end.
3331

3432
%% Function retrieval
3533

3634
import_function(Meta, Name, Arity, S) ->
3735
Tuple = { Name, Arity },
38-
case find_dispatch(Meta, S#elixir_scope.file, Tuple, S#elixir_scope.functions, S#elixir_scope.macros) of
39-
false ->
40-
case find_dispatch(Meta, S#elixir_scope.file, Tuple, S#elixir_scope.macros, S#elixir_scope.functions) of
41-
false -> { { 'fun', ?line(Meta), { function, Name, Arity } }, S };
42-
_ -> false
43-
end;
44-
Receiver ->
36+
case find_dispatch(Meta, Tuple, S#elixir_scope.functions, S#elixir_scope.macros, S#elixir_scope.file) of
37+
{ function, Receiver } ->
4538
elixir_import:record(import, Tuple, Receiver, S#elixir_scope.module),
46-
remote_function(Meta, Receiver, Name, Arity, S)
39+
remote_function(Meta, Receiver, Name, Arity, S);
40+
{ macro, _Receiver } ->
41+
false;
42+
nomatch ->
43+
{ { 'fun', ?line(Meta), { function, Name, Arity } }, S }
4744
end.
4845

4946
require_function(Meta, Receiver, Name, Arity, S) ->
@@ -61,25 +58,25 @@ dispatch_import(Meta, Name, Args, S, Callback) ->
6158
Arity = length(Args),
6259
Tuple = { Name, Arity },
6360

64-
case find_dispatch(Meta, S#elixir_scope.file, Tuple, S#elixir_scope.functions, S#elixir_scope.macros) of
65-
false ->
61+
case find_dispatch(Meta, Tuple, S#elixir_scope.functions, S#elixir_scope.macros, S#elixir_scope.file) of
62+
{ function, Receiver } ->
63+
elixir_import:record(import, Tuple, Receiver, Module),
64+
Endpoint = case (Receiver == ?BUILTIN) andalso is_element(Tuple, in_erlang_functions()) of
65+
true -> erlang;
66+
false -> Receiver
67+
end,
68+
elixir_translator:translate_each({ { '.', Meta, [Endpoint, Name] }, Meta, Args }, S);
69+
Result ->
6670
case expand_import(Meta, Tuple, Args, Module, S#elixir_scope.function,
67-
S#elixir_scope.requires, S#elixir_scope.macros, S#elixir_scope.functions, S) of
71+
S#elixir_scope.requires, S, Result) of
6872
{ error, noexpansion } ->
6973
Callback();
7074
{ error, internal } ->
7175
elixir_import:record(import, Tuple, ?BUILTIN, Module),
7276
elixir_macros:translate({ Name, Meta, Args }, S);
7377
{ ok, _Receiver, Tree } ->
7478
translate_expansion(Meta, Tree, S)
75-
end;
76-
Receiver ->
77-
elixir_import:record(import, Tuple, Receiver, Module),
78-
Endpoint = case (Receiver == ?BUILTIN) andalso is_element(Tuple, in_erlang_functions()) of
79-
true -> erlang;
80-
false -> Receiver
81-
end,
82-
elixir_translator:translate_each({ { '.', Meta, [Endpoint, Name] }, Meta, Args }, S)
79+
end
8380
end.
8481

8582
dispatch_require(Meta, Receiver, Name, Args, S, Callback) ->
@@ -104,29 +101,33 @@ dispatch_require(Meta, Receiver, Name, Args, S, Callback) ->
104101

105102
%% Macros expansion
106103

107-
expand_import(Meta, { Name, Arity } = Tuple, Args, Module, Function, Requires, Macros, Functions, SEnv) ->
108-
case find_dispatch(Meta, elixir_scope:filename(SEnv), Tuple, Macros, Functions) of
109-
false ->
110-
Fun = (Function /= Tuple) andalso
111-
elixir_def_local:macro_for(Tuple, true, Module),
112-
case Fun of
113-
false -> { error, noexpansion };
114-
_ ->
115-
elixir_import:record(import, Tuple, Module, Module),
116-
{ ok, Module, expand_macro_fun(Meta, Fun, Module, Name, Args, Module, Requires, SEnv) }
117-
end;
118-
?BUILTIN ->
104+
expand_import(Meta, { Name, Arity } = Tuple, Args, Module, Function, Requires, SEnv, Result) ->
105+
case Result of
106+
{ macro, ?BUILTIN } ->
119107
case is_element(Tuple, in_erlang_macros()) of
120108
true -> { error, internal };
121109
false ->
122110
elixir_import:record(import, Tuple, ?BUILTIN, Module),
123111
{ ok, ?BUILTIN, expand_macro_named(Meta, ?BUILTIN, Name, Arity, Args, Module, Requires, SEnv) }
124112
end;
125-
Receiver ->
113+
{ macro, Receiver } ->
126114
elixir_import:record(import, Tuple, Receiver, Module),
127-
{ ok, Receiver, expand_macro_named(Meta, Receiver, Name, Arity, Args, Module, Requires, SEnv) }
115+
{ ok, Receiver, expand_macro_named(Meta, Receiver, Name, Arity, Args, Module, Requires, SEnv) };
116+
_ ->
117+
Fun = (Function /= Tuple) andalso
118+
elixir_def_local:macro_for(Tuple, true, Module),
119+
case Fun of
120+
false -> { error, noexpansion };
121+
_ ->
122+
elixir_import:record(import, Tuple, Module, Module),
123+
{ ok, Module, expand_macro_fun(Meta, Fun, Module, Name, Args, Module, Requires, SEnv) }
124+
end
128125
end.
129126

127+
expand_import(Meta, Tuple, Args, Module, Function, Requires, Functions, Macros, SEnv) ->
128+
Result = find_dispatch(Meta, Tuple, Functions, Macros, elixir_scope:filename(SEnv)),
129+
expand_import(Meta, Tuple, Args, Module, Function, Requires, SEnv, Result).
130+
130131
expand_require(Meta, ?BUILTIN, { Name, Arity } = Tuple, Args, Module, _Function, Requires, SEnv) ->
131132
case is_element(Tuple, in_erlang_macros()) of
132133
true -> { error, internal };
@@ -199,26 +200,24 @@ merge_aliases(A1, A2) ->
199200
skip_requires(#elixir_scope{check_requires=false}) -> true;
200201
skip_requires(_) -> false.
201202

202-
find_dispatch(Meta, File, {Name, Arity} = Tuple, List1, List2) ->
203-
Matcher = fun(List) -> lists:filter(fun({_, Vals}) -> is_element(Tuple, Vals) end, List) end,
204-
Matches1 = Matcher(List1),
205-
206-
case length(Matches1) of
207-
0 -> false;
208-
1 ->
209-
Matches2 = Matcher(List2),
203+
find_dispatch(Meta, Tuple, Functions, Macros, File) ->
204+
FunMatch = find_dispatch(Tuple, Functions),
205+
MacMatch = find_dispatch(Tuple, Macros),
210206

211-
case length(Matches2) of
212-
0 -> element(1, hd(Matches1));
213-
_ ->
214-
Err = {ambiguous_call, {element(1, hd(Matches1)), element(1, hd(Matches2)), Name, Arity}},
215-
elixir_errors:form_error(Meta, File, ?MODULE, Err)
216-
end;
207+
case { FunMatch, MacMatch } of
208+
{ [], [Receiver] } -> { macro, Receiver };
209+
{ [Receiver], [] } -> { function, Receiver };
210+
{ [], [] } -> nomatch;
217211
_ ->
218-
Err = {ambiguous_call, {element(1, hd(Matches1)), element(1, hd(tl(Matches1))), Name, Arity}},
212+
{ Name, Arity } = Tuple,
213+
[First, Second|_] = FunMatch ++ MacMatch,
214+
Err = { ambiguous_call, { First, Second, Name, Arity } },
219215
elixir_errors:form_error(Meta, File, ?MODULE, Err)
220216
end.
221217

218+
find_dispatch(Tuple, List) ->
219+
[Receiver || { Receiver, Set } <- List, is_element(Tuple, Set)].
220+
222221
munge_stacktrace(Info, [{ _, _, [S|_], _ }|_], S) ->
223222
[Info];
224223

@@ -233,13 +232,13 @@ munge_stacktrace(_, [], _) ->
233232

234233
%% ERROR HANDLING
235234

236-
format_error({ unrequired_module,{Receiver, Name, Arity, Required }}) ->
235+
format_error({ unrequired_module, { Receiver, Name, Arity, Required }}) ->
237236
String = string:join([elixir_errors:inspect(R) || R <- Required], ", "),
238237
io_lib:format("tried to invoke macro ~ts.~ts/~B but module was not required. Required: ~ts",
239238
[elixir_errors:inspect(Receiver), Name, Arity, String]);
240239

241-
format_error({ ambiguous_call,{Mod1, Mod2, Name, Arity }}) ->
242-
io_lib:format("function ~ts/~B imported from both ~ts and ~ts; call is ambiguous",
240+
format_error({ ambiguous_call, { Mod1, Mod2, Name, Arity }}) ->
241+
io_lib:format("function ~ts/~B imported from both ~ts and ~ts, call is ambiguous",
243242
[Name, Arity, elixir_errors:inspect(Mod1), elixir_errors:inspect(Mod2)]).
244243

245244
%% INTROSPECTION

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ defmodule Kernel.ErrorsTest do
109109
end
110110

111111
test :function_import_conflict do
112-
assert "nofile:2: function exit/1 imported from both erlang and Kernel; call is ambiguous" ==
112+
assert "nofile:2: function exit/1 imported from both erlang and Kernel, call is ambiguous" ==
113113
format_rescue 'defmodule Foo do import :erlang\n def foo, do: exit(:test)\nend'
114114
end
115115

0 commit comments

Comments
 (0)