Skip to content

Commit 531bd8d

Browse files
author
José Valim
committed
Ensure hygiene also works with directl calls to Kernel.function
1 parent a4d8fc2 commit 531bd8d

File tree

5 files changed

+35
-14
lines changed

5 files changed

+35
-14
lines changed

lib/elixir/src/elixir_dispatch.erl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,8 @@ find_import(Meta, Name, Arity, S) ->
2525

2626
case find_dispatch(Meta, Tuple, S) of
2727
{ function, Receiver } -> Receiver;
28-
{ import, Receiver } -> Receiver;
2928
{ macro, Receiver } -> Receiver;
30-
nomatch -> false
29+
_ -> false
3130
end.
3231

3332
%% Function retrieval

lib/elixir/src/elixir_macros.erl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,17 @@ translate({ function, Meta, [[{do,{ '->',_,Pairs}}]] }, S) ->
5959
translate({ function, _, [{ '/', _, [{{ '.', Meta, [M, F] }, _ , []}, A]}] }, S) when is_atom(F), is_integer(A) ->
6060
translate({ function, Meta, [M, F, A] }, S);
6161

62-
translate({ function, _, [{ '/', _, [{F, Meta, C}, A]}] }, S) when is_atom(F), is_integer(A), is_atom(C) ->
62+
translate({ function, MetaFA, [{ '/', _, [{F, Meta, C}, A]}] }, S) when is_atom(F), is_integer(A), is_atom(C) ->
6363
assert_no_match_or_guard_scope(Meta, 'function', S),
6464

65-
case elixir_dispatch:import_function(Meta, F, A, S) of
66-
false -> syntax_error(Meta, S#elixir_scope.file, "cannot convert a macro to a function");
65+
WrappedMeta =
66+
case (lists:keyfind(import, 1, Meta) == false) andalso lists:keyfind(import_fa, 1, MetaFA) of
67+
{ import_fa, Receiver } -> [{ import, Receiver }|Meta];
68+
false -> Meta
69+
end,
70+
71+
case elixir_dispatch:import_function(WrappedMeta, F, A, S) of
72+
false -> syntax_error(WrappedMeta, S#elixir_scope.file, "cannot convert a macro to a function");
6773
Else -> Else
6874
end;
6975

lib/elixir/src/elixir_quote.erl

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,13 @@ do_quote({ quote, _, Args } = Tuple, #elixir_quote{unquote=true} = Q, S) when le
6565
do_quote({ unquote, _Meta, [Expr] }, #elixir_quote{unquote=true}, S) ->
6666
elixir_translator:translate_each(Expr, S);
6767

68-
do_quote({ function, Meta1, [{ '/', Meta2, [{F, Meta3, C}, A]}] } = Function,
68+
do_quote({ function, Meta, [{ '/', _, [{F, _, C}, A]}] = Args },
6969
#elixir_quote{imports_hygiene=true} = Q, S) when is_atom(F), is_integer(A), is_atom(C) ->
70+
do_quote_fa(function, Meta, Args, F, A, Q, S);
7071

71-
case (lists:keyfind(import, 1, Meta3) == false) andalso
72-
elixir_dispatch:find_import(Meta3, F, A, S) of
73-
false ->
74-
do_quote_tuple(Function, Q, S);
75-
Receiver ->
76-
New = { function, Meta1, [{ '/', Meta2, [{F, [{import,Receiver}|Meta3], C}, A]}] },
77-
do_quote_tuple(New, Q, S)
78-
end;
72+
do_quote({ { '.', _, [_, function] } = Target, Meta, [{ '/', _, [{F, _, C}, A]}] = Args },
73+
#elixir_quote{imports_hygiene=true} = Q, S) when is_atom(F), is_integer(A), is_atom(C) ->
74+
do_quote_fa(Target, Meta, Args, F, A, Q, S);
7975

8076
do_quote({ 'alias!', _Meta, [Expr] }, Q, S) ->
8177
do_quote(Expr, Q#elixir_quote{aliases_hygiene=false}, S);
@@ -165,6 +161,16 @@ do_quote_tuple({ Left, Meta, Right }, Q, S) ->
165161
Tuple = { tuple, ?line(Meta), [TLeft, meta(Meta, Q), TRight] },
166162
{ Tuple, RS }.
167163

164+
do_quote_fa(Target, Meta, Args, F, A, Q, S) ->
165+
NewMeta =
166+
case (lists:keyfind(import_fa, 1, Meta) == false) andalso
167+
elixir_dispatch:find_import(Meta, F, A, S) of
168+
false -> Meta;
169+
Receiver -> [{ import_fa, Receiver }|Meta]
170+
end,
171+
172+
do_quote_tuple({ Target, NewMeta, Args }, Q, S).
173+
168174
% Loop through the list finding each unquote_splicing entry.
169175

170176
splice([{ unquote_splicing, _, [Args] }|T], #elixir_quote{unquote=true} = Q, Buffer, Acc, S) ->

lib/elixir/src/elixir_translator.erl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ translate(Forms, S) ->
3535
%% Those macros are "low-level". They are the basic mechanism
3636
%% that makes the language work and cannot be partially applied
3737
%% nor overwritten.
38+
%%
39+
%% =, ^, import, require and alias could be made non-special
40+
%% forms without causing any side effects.
3841

3942
%% Assignment operator
4043

lib/elixir/test/elixir/kernel/quote_test.exs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,18 @@ defmodule Kernel.QuoteTest.ImportsHygieneTest do
248248
end
249249
end
250250

251+
defmacrop get_bin_size_with_kernel_function do
252+
quote do
253+
Kernel.function(size/1).("hello")
254+
end
255+
end
256+
251257
test :expand_imports do
252258
import Kernel, except: [size: 1]
253259
assert get_bin_size == 5
254260
assert get_bin_size_with_partial == 5
255261
assert get_bin_size_with_function == 5
262+
assert get_bin_size_with_kernel_function == 5
256263
end
257264

258265
defmacrop get_dict_size do

0 commit comments

Comments
 (0)