Skip to content

Commit 7196543

Browse files
author
José Valim
committed
Improve how aliases for defmodule are generated
1 parent fade545 commit 7196543

File tree

4 files changed

+104
-32
lines changed

4 files changed

+104
-32
lines changed

lib/elixir/src/elixir_aliases.erl

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
-module(elixir_aliases).
2-
-export([nesting/2, last/1, concat/1, safe_concat/1, lookup/2,
2+
-export([nesting_alias/2, last/1, concat/1, safe_concat/1, lookup/2,
33
format_error/1, ensure_loaded/3, expand/2]).
44
-include("elixir.hrl").
55
-compile({parse_transform, elixir_transform}).
@@ -8,18 +8,18 @@
88
%% Otherwise returns the list of aliases args.
99

1010
expand({ '__aliases__', _Line, [H] }, Aliases) when H /= 'Elixir' ->
11-
expand_alias(H, Aliases);
11+
expand_one(H, Aliases);
1212

1313
expand({ '__aliases__', _Line, [H|T] }, Aliases) when is_atom(H) ->
1414
concat(case H of
1515
'Elixir' -> [H|T];
16-
_ -> [expand_alias(H, Aliases)|T]
16+
_ -> [expand_one(H, Aliases)|T]
1717
end);
1818

1919
expand({ '__aliases__', _Line, List }, _Aliases) ->
2020
List.
2121

22-
expand_alias(H, Aliases) ->
22+
expand_one(H, Aliases) ->
2323
lookup(list_to_atom("Elixir-" ++ atom_to_list(H)), Aliases).
2424

2525
%% Ensure a module is loaded before its usage.
@@ -49,18 +49,29 @@ last([$-|_], Acc) -> Acc;
4949
last([H|T], Acc) -> last(T, [H|Acc]);
5050
last([], Acc) -> Acc.
5151

52-
%% Returns the nesting between two aliases.
53-
54-
nesting(nil, _Full) -> false;
55-
56-
nesting(Prefix, Full) ->
52+
%% Gets two modules names and return an alias
53+
%% which can be passed down to the alias directive
54+
%% and it will create a proper shortcut representing
55+
%% the given nesting.
56+
%%
57+
%% Examples:
58+
%%
59+
%% nesting_alias('Elixir.Foo.Bar', 'Elixir.Foo.Bar.Baz')
60+
%% { '__aliases__', [], ['Elixir', 'Foo', 'Bar', 'Baz'] }
61+
%%
62+
nesting_alias(nil, _Full) -> false;
63+
64+
nesting_alias(Prefix, Full) ->
5765
PrefixList = list_nesting(Prefix),
5866
FullList = list_nesting(Full),
59-
60-
(PrefixList /= []) andalso
61-
(PrefixList /= FullList) andalso
62-
lists:prefix(PrefixList, FullList) andalso
63-
binary_to_atom(<<"Elixir-", (hd(FullList -- PrefixList))/binary>>, utf8).
67+
(PrefixList /= []) andalso do_nesting(PrefixList, FullList, []).
68+
69+
do_nesting([X|PreTail], [X|Tail], Acc) ->
70+
do_nesting(PreTail, Tail, [X|Acc]);
71+
do_nesting([], [H|_], Acc) ->
72+
{ '__aliases__', [], ['Elixir'|[binary_to_atom(X, utf8) || X <- lists:reverse([H|Acc])]] };
73+
do_nesting(_, _, _Acc) ->
74+
false.
6475

6576
list_nesting(Atom) ->
6677
case binary:split(atom_to_binary(Atom, utf8), <<$->>, [global]) of

lib/elixir/src/elixir_macros.erl

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

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

201-
RS = case elixir_aliases:nesting(S#elixir_scope.module, FullModule) of
202-
false -> S;
203-
Alias -> element(2, translate_each({ alias, Meta, [FullModule, [{ as, Alias }]] }, S))
201+
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))
204204
end,
205205

206206
{
@@ -327,14 +327,23 @@ rewrite_case_clauses([{do,[{in,_,[{'_',_,_},[false,nil]]}],False},{do,[{'_',_,_}
327327
rewrite_case_clauses(Clauses) ->
328328
Clauses.
329329

330-
module_ref(Raw, Module, Nesting) when is_atom(Raw); Nesting == nil ->
330+
module_ref(Raw, Module, #elixir_scope{module=Nesting}) when is_atom(Raw); Nesting == nil ->
331331
Module;
332332

333-
module_ref({ '__aliases__', _, ['Elixir'|_] }, Module, _Nesting) ->
333+
module_ref({ '__aliases__', _, ['Elixir'|_] }, Module, _S) ->
334334
Module;
335335

336-
module_ref(_Raw, Module, Nesting) ->
337-
elixir_aliases:concat([Nesting, Module]).
336+
% In case the module is an alias and it was already
337+
% expanded we should not expand it twice
338+
module_ref({ '__aliases__', _, [H|_] }, Module, #elixir_scope{aliases=Aliases} = S) ->
339+
Full = list_to_atom("Elixir-" ++ atom_to_list(H)),
340+
case elixir_aliases:lookup(Full, Aliases) of
341+
Full -> elixir_aliases:concat([S#elixir_scope.module, Module]);
342+
_ -> Module
343+
end;
344+
345+
module_ref(_Raw, Module, S) ->
346+
elixir_aliases:concat([S#elixir_scope.module, Module]).
338347

339348
is_reserved_data(moduledoc) -> true;
340349
is_reserved_data(doc) -> true;

lib/elixir/src/elixir_quote.erl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,15 @@ 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{expand_aliases=false}, S);
5656

57-
do_quote({ '__aliases__', Meta, [H|_] = Aliases }, #elixir_quote{expand_aliases=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__', Meta, [H|_] = Aliases }, #elixir_quote{expand_aliases=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 };
6666

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

lib/elixir/test/elixir/kernel/alias_test.exs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,56 @@ defmodule Kernel.AliasTest do
2626
alias List, as: Nested
2727
assert Nested.flatten([[13]]) == [13]
2828
end
29-
end
29+
end
30+
31+
defmodule Kernel.AliasNestingGenerator do
32+
defmacro create do
33+
quote do
34+
defmodule Parent do
35+
def a, do: :a
36+
end
37+
38+
defmodule Parent.Child do
39+
def b, do: Parent.a
40+
end
41+
end
42+
end
43+
end
44+
45+
defmodule Kernel.AliasNestingTest do
46+
use ExUnit.Case, async: true
47+
48+
require Kernel.AliasNestingGenerator
49+
Kernel.AliasNestingGenerator.create
50+
51+
test :aliases_nesting do
52+
assert Parent.a == :a
53+
assert Parent.Child.b == :a
54+
end
55+
end
56+
57+
defmodule Kernel.FullAliasNestingGenerator do
58+
defmacro create do
59+
quote do
60+
defmodule Parent do
61+
def a, do: :a
62+
end
63+
64+
defmodule Parent.Child do
65+
def b, do: Parent.a
66+
end
67+
end
68+
end
69+
end
70+
71+
defmodule Kernel.FullAliasNestingTest do
72+
use ExUnit.Case, async: true
73+
74+
require Kernel.FullAliasNestingGenerator
75+
Kernel.FullAliasNestingGenerator.create
76+
77+
test :aliases_nesting do
78+
assert Parent.a == :a
79+
assert Parent.Child.b == :a
80+
end
81+
end

0 commit comments

Comments
 (0)