Skip to content

Commit 109c07e

Browse files
author
José Valim
committed
Improve aliases hygiene by using metadata
1 parent eb36c2b commit 109c07e

File tree

4 files changed

+48
-27
lines changed

4 files changed

+48
-27
lines changed

lib/elixir/src/elixir_aliases.erl

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,38 @@
44
-include("elixir.hrl").
55
-compile({parse_transform, elixir_transform}).
66

7-
%% Expand an alias. It returns an atom (mearning that there
7+
%% Expand an alias. It returns an atom (meaning that there
88
%% was an expansion) or a list of atoms.
99

10-
expand({ '__aliases__', _Meta, [H] }, Aliases) when H /= 'Elixir' ->
11-
case expand_one(H, Aliases) of
10+
expand({ '__aliases__', Meta, _ } = Alias, Aliases) ->
11+
case lists:keyfind(alias, 1, Meta) of
12+
{ alias, Atom } when is_atom(Atom) ->
13+
Atom;
14+
false ->
15+
do_expand(Alias, Aliases)
16+
end.
17+
18+
do_expand({ '__aliases__', _Meta, [H] }, Aliases) when H /= 'Elixir' ->
19+
case do_expand_one(H, Aliases) of
1220
false -> [H];
1321
Atom -> Atom
1422
end;
1523

16-
expand({ '__aliases__', _Meta, [H|T] }, Aliases) when is_atom(H) ->
24+
do_expand({ '__aliases__', _Meta, [H|T] }, Aliases) when is_atom(H) ->
1725
case H of
1826
'Elixir' ->
1927
concat(T);
2028
_ ->
21-
case expand_one(H, Aliases) of
29+
case do_expand_one(H, Aliases) of
2230
false -> [H|T];
2331
Atom -> concat([Atom|T])
2432
end
2533
end;
2634

27-
expand({ '__aliases__', _Meta, List }, _Aliases) ->
35+
do_expand({ '__aliases__', _Meta, List }, _Aliases) ->
2836
List.
2937

30-
expand_one(H, Aliases) ->
38+
do_expand_one(H, Aliases) ->
3139
Lookup = list_to_atom("Elixir-" ++ atom_to_list(H)),
3240
case lookup(Lookup, Aliases) of
3341
Lookup -> false;
@@ -69,7 +77,7 @@ last([], Acc) -> Acc.
6977
%% Examples:
7078
%%
7179
%% nesting_alias('Elixir.Foo.Bar', 'Elixir.Foo.Bar.Baz.Bat')
72-
%% { '__aliases__', [], ['Elixir', 'Foo', 'Bar', 'Baz'] }
80+
%% { 'Elixir.Baz', 'Elixir.Foo.Bar.Baz' }
7381
%%
7482
%% When passed to alias, the example above will generate an
7583
%% alias like:
@@ -86,7 +94,7 @@ nesting_alias(Prefix, Full) ->
8694
do_nesting([X|PreTail], [X|Tail], Acc) ->
8795
do_nesting(PreTail, Tail, [X|Acc]);
8896
do_nesting([], [H|_], Acc) ->
89-
{ '__aliases__', [], ['Elixir'|[list_to_atom(X) || X <- lists:reverse([H|Acc])]] };
97+
{ list_to_atom("Elixir-" ++ H), concat(lists:reverse([H|Acc])) };
9098
do_nesting(_, _, _Acc) ->
9199
false.
92100

lib/elixir/src/elixir_macros.erl

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,13 @@ translate({defmodule, Meta, [Ref, KV]}, S) ->
196196

197197
{ FRef, FS } = case TRef of
198198
{ atom, _, Module } ->
199-
FullModule = module_ref(Ref, Module, S),
199+
FullModule = expand_module(Ref, Module, S),
200200

201201
RS = case elixir_aliases:nesting_alias(S#elixir_scope.module, FullModule) of
202-
false -> S;
203-
Nesting -> element(2, translate_each({ alias, Meta, [Nesting] }, S))
202+
{ New, Old } ->
203+
S#elixir_scope{aliases=orddict:store(New, Old, S#elixir_scope.aliases)};
204+
false ->
205+
S
204206
end,
205207

206208
{
@@ -327,18 +329,18 @@ rewrite_case_clauses([{do,[{in,_,[{'_',_,_},[false,nil]]}],False},{do,[{'_',_,_}
327329
rewrite_case_clauses(Clauses) ->
328330
Clauses.
329331

330-
module_ref(Raw, Module, #elixir_scope{module=Nesting}) when is_atom(Raw); Nesting == nil ->
332+
expand_module(Raw, Module, #elixir_scope{module=Nesting}) when is_atom(Raw); Nesting == nil ->
331333
Module;
332334

333-
module_ref({ '__aliases__', _, _ } = Alias, Module, S) ->
335+
expand_module({ '__aliases__', _, _ } = Alias, Module, S) ->
334336
case elixir_aliases:expand(Alias, S#elixir_scope.aliases) of
335337
Atom when is_atom(Atom) ->
336338
Module;
337339
Aliases when is_list(Aliases) ->
338340
elixir_aliases:concat([S#elixir_scope.module, Module])
339341
end;
340342

341-
module_ref(_Raw, Module, S) ->
343+
expand_module(_Raw, Module, S) ->
342344
elixir_aliases:concat([S#elixir_scope.module, Module]).
343345

344346
is_reserved_data(moduledoc) -> true;

lib/elixir/src/elixir_quote.erl

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,20 @@ do_quote({ unquote, _Meta, [Expr] }, #elixir_quote{unquote=true}, S) ->
5454
do_quote({ 'alias!', _Meta, [Expr] }, Q, S) ->
5555
do_quote(Expr, Q#elixir_quote{aliases_hygiene=false}, S);
5656

57-
% do_quote({ '__aliases__', Meta, [H|_] = Aliases }, #elixir_quote{aliases_hygiene=true} = Q, S) when is_atom(H) and H /= 'Elixir' ->
58-
% Line = ?line(Meta),
59-
% { TAliases, SA } = do_quote(['Elixir'|Aliases], Q, S),
60-
%
61-
% { { tuple, Line, [
62-
% { atom, Line, '__aliases__' },
63-
% meta(Meta, Q),
64-
% TAliases
65-
% ] }, SA };
57+
do_quote({ '__aliases__', RawMeta, [H|T] } = Alias, #elixir_quote{aliases_hygiene=true} = Q, S) when is_atom(H) and (H /= 'Elixir') ->
58+
Meta = case elixir_aliases:expand(Alias, S#elixir_scope.aliases) of
59+
Atom when is_atom(Atom) -> [{alias,Atom}|RawMeta];
60+
Aliases when is_list(Aliases) -> RawMeta
61+
end,
62+
63+
Line = ?line(Meta),
64+
{ TAliases, SA } = do_quote([H|T], Q, S),
65+
66+
{ { tuple, Line, [
67+
{ atom, Line, '__aliases__' },
68+
meta(Meta, Q),
69+
TAliases
70+
] }, SA };
6671

6772
do_quote({ { { '.', Meta, [Left, unquote] }, _, [Expr] }, _, Args }, #elixir_quote{unquote=true} = Q, S) ->
6873
All = [Left, { unquote, Meta, [Expr] }, Args, S#elixir_scope.file],

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,16 @@ end
157157
defmodule Kernel.QuoteTest.AliasHygieneTest do
158158
use ExUnit.Case, async: true
159159

160+
alias Dict, as: SuperDict
161+
160162
test :expand_aliases do
161-
assert Code.eval_quoted(quote do: Foo.Bar) == { Elixir.Foo.Bar, [] }
162-
assert Code.eval_quoted(quote do: alias!(Foo.Bar)) == { Foo.Bar, [] }
163-
assert Code.eval_quoted(quote expand_aliases: false, do: Foo.Bar) == { Foo.Bar, [] }
163+
assert quote(do: Foo.Bar) == { :__aliases__, [], [:Foo, :Bar] }
164+
assert quote(do: Dict.Bar) == { :__aliases__, [], [:Dict, :Bar] }
165+
assert quote(do: SuperDict.Bar) == { :__aliases__, [alias: Dict.Bar], [:SuperDict, :Bar] }
166+
assert quote(do: alias!(SuperDict.Bar)) == { :__aliases__, [], [:SuperDict, :Bar] }
167+
168+
assert Code.eval_quoted(quote do: SuperDict.Bar) == { Elixir.Dict.Bar, [] }
169+
assert Code.eval_quoted(quote do: alias!(SuperDict.Bar)) == { Elixir.SuperDict.Bar, [] }
164170
end
165171
end
166172

0 commit comments

Comments
 (0)