Skip to content

Commit 86e7069

Browse files
author
José Valim
committed
Clean up how we store recorded locals in the imports table
1 parent 334f3ce commit 86e7069

File tree

4 files changed

+52
-69
lines changed

4 files changed

+52
-69
lines changed

lib/elixir/src/elixir_def_local.erl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@
99
-include("elixir.hrl").
1010

1111
%% Used by elixir_dispatch, returns false if no macro is found
12-
macro_for(_Tuple, _All, nil) -> false;
12+
macro_for(_Tuple, _All, #elixir_scope{module=nil}) -> false;
1313

14-
macro_for(Tuple, All, Module) ->
14+
macro_for(Tuple, All, #elixir_scope{module=Module} = S) ->
1515
try elixir_def:lookup_definition(Module, Tuple) of
1616
{ { Tuple, Kind, Line, _, _, _, _ }, Clauses } when Kind == defmacro; All, Kind == defmacrop ->
17-
%% This function is only called if S#elixir_scope.function /= Tuple
18-
elixir_import:record(Tuple, Module, Module),
17+
elixir_import:record_local(Tuple, S),
1918
get_function(Line, Module, Clauses);
2019
_ ->
2120
false

lib/elixir/src/elixir_dispatch.erl

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,7 @@ import_function(Meta, Name, Arity, S) ->
4141
{ import, Receiver } ->
4242
require_function(Meta, Receiver, Name, Arity, S);
4343
nomatch ->
44-
Module = S#elixir_scope.module,
45-
case S#elixir_scope.function of
46-
Tuple -> ok;
47-
_ -> elixir_import:record(Tuple, Module, Module)
48-
end,
44+
elixir_import:record_local(Tuple, S),
4945
{ { 'fun', ?line(Meta), { function, Name, Arity } }, S }
5046
end.
5147

@@ -128,7 +124,7 @@ do_expand_import(Meta, { Name, Arity } = Tuple, Args, Module, S, Result) ->
128124
expand_require(Meta, Receiver, Tuple, Args, Module, S);
129125
_ ->
130126
Fun = (S#elixir_scope.function /= Tuple) andalso
131-
elixir_def_local:macro_for(Tuple, true, Module),
127+
elixir_def_local:macro_for(Tuple, true, S),
132128
case Fun of
133129
false -> { error, noexpansion };
134130
_ ->
@@ -148,7 +144,7 @@ expand_require(Meta, ?BUILTIN, { Name, Arity } = Tuple, Args, Module, S) ->
148144

149145
expand_require(Meta, Receiver, { Name, Arity } = Tuple, Args, Module, S) ->
150146
Fun = (Module == Receiver) andalso (S#elixir_scope.function /= Tuple) andalso
151-
elixir_def_local:macro_for(Tuple, false, Module),
147+
elixir_def_local:macro_for(Tuple, false, S),
152148

153149
case Fun of
154150
false ->

lib/elixir/src/elixir_import.erl

Lines changed: 44 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@
22
%% in between local functions and imports.
33
%% For imports dispatch, please check elixir_dispatch.
44
-module(elixir_import).
5-
-export([import/5, recorded_locals/1, format_error/1,
5+
-export([import/5, record_local/2, recorded_locals/1, format_error/1,
66
ensure_no_import_conflict/4, ensure_no_local_conflict/4,
77
ensure_all_imports_used/3,
88
build_table/1, delete_table/1, record/3]).
99
-include("elixir.hrl").
1010

11+
%% This table keeps:
12+
%%
13+
%% * Invoked imports and requires in the format { { Name, Arity }, Module }
14+
%% * The current warn status imports and requires in the format { Module, Line :: integer }
15+
%% * Invoked locals in the format { { Name, Arity }, Public :: boolean }
16+
%%
1117
table(Module) -> ?atom_concat([i, Module]).
1218

1319
build_table(Module) ->
@@ -16,18 +22,20 @@ build_table(Module) ->
1622
delete_table(Module) ->
1723
ets:delete(table(Module)).
1824

19-
record(_Tuple, _Receiver, nil) ->
20-
false;
21-
25+
record(_Tuple, _Receiver, nil) -> false;
2226
record(Tuple, Receiver, Module) ->
2327
try
2428
ets:insert(table(Module), { Tuple, Receiver })
2529
catch
2630
error:badarg -> false
2731
end.
2832

29-
record_warn(_Meta, _Ref, _Opts, #elixir_scope{module=nil}) -> false;
33+
record_local(Tuple, #elixir_scope{function=Function})
34+
when Function == nil; Function == Tuple -> false;
35+
record_local(Tuple, #elixir_scope{module=Module}) ->
36+
record(Tuple, true, Module).
3037

38+
record_warn(_Meta, _Ref, _Opts, #elixir_scope{module=nil}) -> false;
3139
record_warn(Meta, Ref, Opts, S) ->
3240
Table = table(S#elixir_scope.module),
3341
ets:delete(Table, Ref),
@@ -43,10 +51,15 @@ record_warn(Meta, Ref, Opts, S) ->
4351

4452
recorded_locals(Module) ->
4553
Table = table(Module),
46-
Match = { '$1', Module },
47-
Result = ets:match(Table, Match),
48-
ets:match_delete(Table, Match),
49-
lists:append(Result).
54+
Match = module_local_spec(),
55+
Result = ets:select(Table, Match),
56+
ets:select_delete(Table, Match),
57+
Result.
58+
59+
module_local_spec() ->
60+
[{ { '$1', '$2' }, [{ 'orelse', {'==','$2',true}, {'==','$2',false} }], ['$1'] }].
61+
62+
%% IMPORT HELPERS
5063

5164
%% Update the scope to consider the imports for aliases
5265
%% based on the given options and selector.
@@ -80,16 +93,13 @@ import(Meta, Ref, Opts, Selector, S) ->
8093
record_warn(Meta, Ref, Opts, S),
8194
SM.
8295

83-
%% IMPORT FUNCTION RELATED HELPERS
84-
8596
%% Calculates the imports based on only and except
8697

8798
calculate(Meta, Key, Opts, Old, Temp, AvailableFun, S) ->
8899
File = S#elixir_scope.file,
89100

90101
New = case keyfind(only, Opts) of
91-
{ only, RawOnly } ->
92-
Only = expand_fun_arity(Meta, only, RawOnly, S),
102+
{ only, Only } ->
93103
case Only -- get_exports(Key) of
94104
[{Name,Arity}|_] ->
95105
Tuple = { invalid_import, { Key, Name, Arity } },
@@ -101,8 +111,7 @@ calculate(Meta, Key, Opts, Old, Temp, AvailableFun, S) ->
101111
case keyfind(except, Opts) of
102112
false -> AvailableFun(true);
103113
{ except, [] } -> AvailableFun(true);
104-
{ except, RawExcept } ->
105-
Except = expand_fun_arity(Meta, except, RawExcept, S),
114+
{ except, Except } ->
106115
case keyfind(Key, Old) of
107116
false -> AvailableFun(true) -- Except;
108117
{Key,OldImports} -> OldImports -- Except
@@ -134,29 +143,6 @@ if_quoted(Meta, Temp, Callback) ->
134143
Temp
135144
end.
136145

137-
%% Ensure we are expanding macros and stuff
138-
139-
expand_fun_arity(Meta, Kind, Value, S) ->
140-
{ TValue, _S } = elixir_translator:translate_each(Value, S),
141-
cons_to_keywords(Meta, Kind, TValue, S).
142-
143-
cons_to_keywords(Meta, Kind, { cons, _, Left, { nil, _ } }, S) ->
144-
[tuple_to_fun_arity(Meta, Kind, Left, S)];
145-
146-
cons_to_keywords(Meta, Kind, { cons, _, Left, Right }, S) ->
147-
[tuple_to_fun_arity(Meta, Kind, Left, S)|cons_to_keywords(Meta, Kind, Right, S)];
148-
149-
cons_to_keywords(Meta, Kind, _, S) ->
150-
elixir_errors:syntax_error(Meta, S#elixir_scope.file,
151-
"invalid value for :~ts, expected a list with functions and arities", [Kind]).
152-
153-
tuple_to_fun_arity(_Meta, _Kind, { tuple, _, [{ atom, _, Atom }, { integer, _, Integer }] }, _S) ->
154-
{ Atom, Integer };
155-
156-
tuple_to_fun_arity(Meta, Kind, _, S) ->
157-
elixir_errors:syntax_error(Meta, S#elixir_scope.file,
158-
"invalid value for :~ts, expected a list with functions and arities", [Kind]).
159-
160146
%% Retrieve functions and macros from modules
161147

162148
get_exports(Module) ->
@@ -207,26 +193,33 @@ ensure_no_local_conflict(Meta, File, Module, AllDefined) ->
207193

208194
ensure_no_import_conflict(Meta, File, Module, AllDefined) ->
209195
Table = table(Module),
210-
Matches = [X || X <- AllDefined, ets:member(Table, X)],
196+
[ensure_no_import_conflict(Meta, File, Module, Table, X) || X <- AllDefined],
197+
ok.
198+
199+
ensure_no_import_conflict(Meta, File, Module, Table, { Name, Arity } = Tuple) ->
200+
RawMatches = ets:match(Table, { Tuple, '$1' }),
201+
Matches = [X || X <- lists:append(RawMatches), not is_boolean(X), X /= Module],
211202

212203
case Matches of
213-
[{Name,Arity}|_] ->
214-
Key = ets:lookup_element(Table, { Name, Arity }, 2),
215-
Tuple = { import_conflict, { hd(Key), Name, Arity } },
216-
elixir_errors:form_error(Meta, File, ?MODULE, Tuple);
217-
[] ->
218-
ok
204+
[] -> ok;
205+
Key ->
206+
Error = { import_conflict, { hd(Key), Name, Arity } },
207+
elixir_errors:form_error(Meta, File, ?MODULE, Error)
219208
end.
220209

210+
%% Ensure all imports are used by checking all
211+
%% enabled warnings in the table with the imported
212+
%% function calls.
213+
221214
ensure_all_imports_used(_Line, File, Module) ->
222215
Table = table(Module),
223-
[begin
224-
elixir_errors:handle_file_warning(File, { L, ?MODULE, { unused_import, M } })
225-
end || [M, L] <- ets:select(Table, module_line_spec()),
226-
ets:match(Table, { '$1', M }) == []].
216+
[ begin
217+
elixir_errors:handle_file_warning(File, { L, ?MODULE, { unused_import, M } })
218+
end || { M, L } <- ets:select(Table, module_line_spec()),
219+
ets:match(Table, { '$1', M }) == []].
227220

228221
module_line_spec() ->
229-
[{ { '$1', '$2' }, [{ is_integer, '$2' }], ['$$'] }].
222+
[{ { '$1', '$2' }, [{ is_integer, '$2' }], ['$_'] }].
230223

231224
%% Ensure the given functions don't clash with any
232225
%% of Elixir non overridable macros.
@@ -287,8 +280,6 @@ intersection([H|T], All) ->
287280

288281
intersection([], _All) -> [].
289282

290-
%% INTROSPECTION
291-
292283
%% Internal funs that are never imported etc.
293284

294285
remove_underscored(default, List) -> remove_underscored(List);
@@ -308,7 +299,7 @@ remove_internals(Set) ->
308299
ordsets:del_element({ module_info, 1 },
309300
ordsets:del_element({ module_info, 0 }, Set)).
310301

311-
%% Macros implemented in Erlang that are not overridable.
302+
%% Macros implemented in Erlang that are not importable.
312303

313304
special_form() ->
314305
[

lib/elixir/src/elixir_translator.erl

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -577,11 +577,8 @@ translate_fn(Meta, Clauses, S) ->
577577

578578
%% Locals
579579

580-
translate_local(Meta, Name, Args, #elixir_scope{local=nil,module=Module,function=Function} = S) ->
581-
case { Name, length(Args) } of
582-
Function -> ok;
583-
Tuple -> elixir_import:record(Tuple, Module, Module)
584-
end,
580+
translate_local(Meta, Name, Args, #elixir_scope{local=nil} = S) ->
581+
elixir_import:record_local({ Name, length(Args) }, S),
585582
Line = ?line(Meta),
586583
{ TArgs, NS } = translate_args(Args, S),
587584
{ { call, Line, { atom, Line, Name }, TArgs }, NS };

0 commit comments

Comments
 (0)