Skip to content

Commit 169595f

Browse files
committed
Change import metadata to imports as a list
This is preparation to better ambiguity solving of quoted expressions.
1 parent 197b79f commit 169595f

File tree

7 files changed

+67
-46
lines changed

7 files changed

+67
-46
lines changed

lib/elixir/lib/macro.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ defmodule Macro do
187187
188188
* `:alias` - Used for alias hygiene.
189189
* `:ambiguous_op` - Used for improved error messages in the compiler.
190-
* `:import` - Used for import hygiene.
190+
* `:imports` - Used for import hygiene.
191191
* `:var` - Used for improved error messages on undefined variables.
192192
193193
Do not rely on them as they may change or be fully removed in future versions

lib/elixir/src/elixir_dispatch.erl

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
require_function/5, import_function/4,
77
expand_import/7, expand_require/6,
88
default_functions/0, default_macros/0, default_requires/0,
9-
find_import/4, format_error/1]).
9+
find_import/4, find_imports/4, format_error/1]).
1010
-include("elixir.hrl").
1111
-import(ordsets, [is_element/2]).
1212
-define(kernel, 'Elixir.Kernel').
@@ -36,6 +36,20 @@ find_import(Meta, Name, Arity, E) ->
3636
false
3737
end.
3838

39+
find_imports(Meta, Name, Arity, E) ->
40+
Tuple = {Name, Arity},
41+
42+
case find_dispatch(Meta, Tuple, [], E) of
43+
{function, Receiver} ->
44+
elixir_env:trace({imported_function, Meta, Receiver, Name, Arity}, E),
45+
[{Receiver, Arity}];
46+
{macro, Receiver} ->
47+
elixir_env:trace({imported_macro, Meta, Receiver, Name, Arity}, E),
48+
[{Receiver, Arity}];
49+
_ ->
50+
[]
51+
end.
52+
3953
%% Function retrieval
4054

4155
import_function(Meta, Name, Arity, E) ->
@@ -233,8 +247,8 @@ caller(Line, E) ->
233247
required(Meta) ->
234248
lists:keyfind(required, 1, Meta) == {required, true}.
235249

236-
find_dispatch(Meta, Tuple, Extra, E) ->
237-
case is_import(Meta) of
250+
find_dispatch(Meta, {_Name, Arity} = Tuple, Extra, E) ->
251+
case is_import(Meta, Arity) of
238252
{import, _} = Import ->
239253
Import;
240254
false ->
@@ -258,11 +272,15 @@ find_dispatch(Meta, Tuple, Extra, E) ->
258272
find_dispatch(Tuple, List) ->
259273
[Receiver || {Receiver, Set} <- List, is_element(Tuple, Set)].
260274

261-
is_import(Meta) ->
262-
case lists:keyfind(import, 1, Meta) of
263-
{import, _} = Import ->
275+
is_import(Meta, Arity) ->
276+
case lists:keyfind(imports, 1, Meta) of
277+
{imports, Imports} ->
264278
case lists:keyfind(context, 1, Meta) of
265-
{context, _} -> Import;
279+
{context, _} ->
280+
case lists:keyfind(Arity, 2, Imports) of
281+
{Receiver, Arity} -> {import, Receiver};
282+
false -> false
283+
end;
266284
false -> false
267285
end;
268286
false -> false

lib/elixir/src/elixir_parser.yrl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ Right 80 assoc_op_eol. %% =>
6666
Nonassoc 90 capture_op_eol. %% &
6767
Right 100 match_op_eol. %% =
6868
Left 110 or_op_eol. %% ||, |||, or
69-
% Left 120 xor_op_eol. %% ^^^
7069
Left 130 and_op_eol. %% &&, &&&, and
7170
Left 140 comp_op_eol. %% ==, !=, =~, ===, !==
7271
Left 150 rel_op_eol. %% <, >, <=, >=

lib/elixir/src/elixir_quote.erl

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,8 @@ do_quote({unquote, _Meta, [Expr]}, #elixir_quote{unquote=true}, _) ->
290290

291291
%% Aliases
292292

293-
do_quote({'__aliases__', Meta, [H | T]} = Alias, #elixir_quote{aliases_hygiene=true} = Q, E) when is_atom(H) and (H /= 'Elixir') ->
293+
do_quote({'__aliases__', Meta, [H | T]} = Alias, #elixir_quote{aliases_hygiene=true} = Q, E)
294+
when is_atom(H), H /= 'Elixir' ->
294295
Annotation =
295296
case elixir_aliases:expand(Alias, E) of
296297
Atom when is_atom(Atom) -> Atom;
@@ -301,12 +302,14 @@ do_quote({'__aliases__', Meta, [H | T]} = Alias, #elixir_quote{aliases_hygiene=t
301302

302303
%% Vars
303304

304-
do_quote({Name, Meta, nil}, #elixir_quote{vars_hygiene=true, imports_hygiene=true} = Q, E) when is_atom(Name) ->
305-
ImportMeta = import_meta(Meta, Name, 0, Q, E),
306-
{'{}', [], [Name, meta(ImportMeta, Q), Q#elixir_quote.context]};
305+
do_quote({Name, Meta, nil}, #elixir_quote{vars_hygiene=true} = Q, E)
306+
when is_atom(Name), is_list(Meta) ->
307+
ImportMeta = if
308+
Q#elixir_quote.imports_hygiene -> import_meta(Meta, Name, 0, Q, E);
309+
true -> Meta
310+
end,
307311

308-
do_quote({Name, Meta, nil}, #elixir_quote{vars_hygiene=true} = Q, _E) when is_atom(Name) ->
309-
{'{}', [], [Name, meta(Meta, Q), Q#elixir_quote.context]};
312+
{'{}', [], [Name, meta(ImportMeta, Q), Q#elixir_quote.context]};
310313

311314
%% Unquote
312315

@@ -320,13 +323,26 @@ do_quote({{'.', Meta, [Left, unquote]}, _, [Expr]}, #elixir_quote{unquote=true}
320323

321324
do_quote({'&', Meta, [{'/', _, [{F, _, C}, A]}] = Args},
322325
#elixir_quote{imports_hygiene=true} = Q, E) when is_atom(F), is_integer(A), is_atom(C) ->
323-
do_quote_fa('&', Meta, Args, F, A, Q, E);
326+
NewMeta =
327+
case elixir_dispatch:find_import(Meta, F, A, E) of
328+
false ->
329+
Meta;
324330

325-
do_quote({Name, Meta, Args}, #elixir_quote{imports_hygiene=true} = Q, E) when is_atom(Name), is_list(Args) ->
326-
do_quote_import(Meta, Name, length(Args), Args, Q, E);
331+
Receiver ->
332+
keystore(context, keystore(imports, Meta, [{Receiver, A}]), Q#elixir_quote.context)
333+
end,
334+
do_quote_tuple('&', NewMeta, Args, Q, E);
335+
336+
do_quote({Name, Meta, ArgsOrContext}, #elixir_quote{imports_hygiene=true} = Q, E)
337+
when is_atom(Name), is_list(Meta), is_list(ArgsOrContext) or is_atom(ArgsOrContext) ->
338+
Arity = if
339+
is_atom(ArgsOrContext) -> 0;
340+
true -> length(ArgsOrContext)
341+
end,
327342

328-
do_quote({Name, Meta, Context}, #elixir_quote{imports_hygiene=true} = Q, E) when is_atom(Name), is_atom(Context) ->
329-
do_quote_import(Meta, Name, 0, Context, Q, E);
343+
ImportMeta = import_meta(Meta, Name, Arity, Q, E),
344+
Annotated = annotate({Name, ImportMeta, ArgsOrContext}, Q#elixir_quote.context),
345+
do_quote_tuple(Annotated, Q, E);
330346

331347
%% Two-element tuples
332348

@@ -424,40 +440,24 @@ bad_escape(Arg) ->
424440

425441
import_meta(Meta, Name, Arity, Q, E) ->
426442
case (keyfind(import, Meta) == false) andalso
427-
elixir_dispatch:find_import(Meta, Name, Arity, E) of
428-
false ->
443+
elixir_dispatch:find_imports(Meta, Name, Arity, E) of
444+
[] ->
429445
case (Arity == 1) andalso keyfind(ambiguous_op, Meta) of
430446
{ambiguous_op, nil} -> keystore(ambiguous_op, Meta, Q#elixir_quote.context);
431447
_ -> Meta
432448
end;
433-
Receiver ->
434-
keystore(import, keystore(context, Meta, Q#elixir_quote.context), Receiver)
449+
450+
Imports ->
451+
keystore(imports, keystore(context, Meta, Q#elixir_quote.context), Imports)
435452
end.
436453

437454
%% do_quote_*
438455

439-
do_quote_import(Meta, Name, Arity, ArgsOrAtom, Q, E) ->
440-
ImportMeta = import_meta(Meta, Name, Arity, Q, E),
441-
Annotated = annotate({Name, ImportMeta, ArgsOrAtom}, Q#elixir_quote.context),
442-
do_quote_tuple(Annotated, Q, E).
443-
444456
do_quote_call(Left, Meta, Expr, Args, Q, E) ->
445457
All = [Left, {unquote, Meta, [Expr]}, Args, Q#elixir_quote.context],
446458
TAll = [do_quote(X, Q, E) || X <- All],
447459
{{'.', Meta, [elixir_quote, dot]}, Meta, [meta(Meta, Q) | TAll]}.
448460

449-
do_quote_fa(Target, Meta, Args, F, A, Q, E) ->
450-
NewMeta =
451-
case elixir_dispatch:find_import(Meta, F, A, E) of
452-
false -> Meta;
453-
Receiver ->
454-
lists:keystore(context, 1,
455-
lists:keystore(import, 1, Meta, {import, Receiver}),
456-
{context, Q#elixir_quote.context}
457-
)
458-
end,
459-
do_quote_tuple(Target, NewMeta, Args, Q, E).
460-
461461
do_quote_tuple({Left, Meta, Right}, Q, E) ->
462462
do_quote_tuple(Left, Meta, Right, Q, E).
463463

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ defmodule Kernel.ExpansionTest do
418418
test "in guards" do
419419
code = quote(do: fn pid when :erlang.==(pid, self) -> pid end)
420420
expanded_code = quote(do: fn pid when :erlang.==(pid, :erlang.self()) -> pid end)
421-
assert clean_meta(expand(code), [:import, :context]) == expanded_code
421+
assert clean_meta(expand(code), [:imports, :context]) == expanded_code
422422

423423
message = ~r"cannot find or invoke local foo/1"
424424

@@ -1061,10 +1061,11 @@ defmodule Kernel.ExpansionTest do
10611061

10621062
test "expands remotes" do
10631063
assert expand(quote(do: &List.flatten/2)) ==
1064-
quote(do: &:"Elixir.List".flatten/2) |> clean_meta([:import, :context, :no_parens])
1064+
quote(do: &:"Elixir.List".flatten/2)
1065+
|> clean_meta([:imports, :context, :no_parens])
10651066

10661067
assert expand(quote(do: &Kernel.is_atom/1)) ==
1067-
quote(do: &:erlang.is_atom/1) |> clean_meta([:import, :context, :no_parens])
1068+
quote(do: &:erlang.is_atom/1) |> clean_meta([:imports, :context, :no_parens])
10681069
end
10691070

10701071
test "expands macros" do

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,6 @@ defmodule Kernel.QuoteTest.ImportsHygieneTest do
631631
test "checks the context also for variables to zero-arity functions" do
632632
import BinaryUtils
633633
{:int32, meta, __MODULE__} = quote(do: int32)
634-
assert meta[:import] == BinaryUtils
634+
assert meta[:imports] == [{BinaryUtils, 0}]
635635
end
636636
end

lib/elixir/test/elixir/protocol/consolidation_test.exs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,10 @@ defmodule Protocol.ConsolidationTest do
131131
end
132132

133133
test "consolidation errors on missing BEAM files" do
134-
defprotocol(NoBeam, do: nil)
134+
defprotocol NoBeam do
135+
def example(arg)
136+
end
137+
135138
assert Protocol.consolidate(String, []) == {:error, :not_a_protocol}
136139
assert Protocol.consolidate(NoBeam, []) == {:error, :no_beam_info}
137140
end

0 commit comments

Comments
 (0)