Skip to content

Commit 99da29b

Browse files
author
José Valim
committed
Ensure eval callbacks gets a fresh vars dict
1 parent 3c3c989 commit 99da29b

File tree

4 files changed

+48
-41
lines changed

4 files changed

+48
-41
lines changed

lib/elixir/src/elixir.erl

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -137,48 +137,18 @@ translate_forms(Tree, Binding, Opts) when is_list(Opts) ->
137137
translate_forms(Tree, Binding, scope_for_eval(Opts));
138138

139139
translate_forms(Tree, Binding, #elixir_scope{} = Scope) ->
140-
elixir_translator:translate(Tree, Scope#elixir_scope{
141-
vars=binding_dict(Binding),
142-
temp_vars=[],
143-
clause_vars=nil,
144-
counter=[]
145-
}).
140+
elixir_translator:translate(Tree, elixir_scope:vars_from_binding(Scope, Binding)).
146141

147142
eval_forms(Tree, Binding, Scope) ->
148143
{ ParseTree, NewScope } = translate_forms(Tree, Binding, Scope),
149144
case ParseTree of
150145
[] -> { nil, Binding, NewScope };
151146
_ ->
152-
{value, Value, NewBinding} = erl_eval:exprs(ParseTree, normalize_binding(Binding)),
153-
{Value, final_binding(NewBinding, NewScope#elixir_scope.vars), NewScope }
147+
{value, Value, NewBinding} = erl_eval:exprs(ParseTree, elixir_scope:binding_for_eval(Binding, nil)),
148+
{Value, elixir_scope:binding_from_vars(NewScope, NewBinding), NewScope }
154149
end.
155150

156151
%% INTERNAL HELPERS
157152

158153
to_binary(Bin) when is_binary(Bin) -> Bin;
159154
to_binary(List) when is_list(List) -> list_to_binary(List).
160-
161-
binding_dict(List) -> binding_dict(List, orddict:new()).
162-
binding_dict([{{H,Kind},_}|T], Dict) -> binding_dict(T, orddict:store({ H, Kind }, H, Dict));
163-
binding_dict([{H,_}|T], Dict) -> binding_dict(T, orddict:store({ H, nil }, H, Dict));
164-
binding_dict([], Dict) -> Dict.
165-
166-
final_binding(Binding, Vars) -> final_binding(Binding, [], Binding, Vars).
167-
final_binding([{Var,_}|T], Acc, Binding, Vars) ->
168-
case lists:member($@, atom_to_list(Var)) of
169-
true ->
170-
final_binding(T, Acc, Binding, Vars);
171-
false ->
172-
RealName = orddict:fetch({ Var, nil }, Vars),
173-
RealValue = proplists:get_value(RealName, Binding, nil),
174-
final_binding(T, [{Var, RealValue}|Acc], Binding, Vars)
175-
end;
176-
177-
final_binding([], Acc, _Binding, _Vars) -> lists:reverse(Acc).
178-
179-
normalize_binding(Binding) ->
180-
Keyword = orddict:from_list(Binding),
181-
case orddict:find('_@MODULE', Keyword) of
182-
{ ok, _ } -> Keyword;
183-
_ -> orddict:store('_@MODULE', nil, Keyword)
184-
end.

lib/elixir/src/elixir_compiler.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,12 @@ eval_forms(Forms, Line, Vars, S) ->
8484
%% Compile the module by forms based on the scope information
8585
%% executes the callback in case of success. This automatically
8686
%% handles errors and warnings. Used by this module and elixir_module.
87-
module(Forms, S, Callback) ->
87+
module(Forms, File, Callback) ->
8888
Options = case get_opt(debug_info) of
8989
true -> [debug_info];
9090
_ -> []
9191
end,
92-
module(Forms, S#elixir_scope.file, Options, false, Callback).
92+
module(Forms, File, Options, false, Callback).
9393

9494
module(Forms, File, RawOptions, Bootstrap, Callback) when
9595
is_binary(File), is_list(Forms), is_list(RawOptions), is_boolean(Bootstrap), is_function(Callback) ->

lib/elixir/src/elixir_module.erl

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
-define(persisted_attr, '__persisted_attributes').
99

1010
eval_quoted(Module, Quoted, RawBinding, Opts) ->
11-
Binding = binding_for_eval(Module, RawBinding),
11+
Binding = elixir_scope:binding_for_eval(RawBinding, Module),
1212
Scope = scope_for_eval(Module, Opts),
1313

1414
elixir_def:reset_last(Module),
@@ -27,8 +27,6 @@ scope_for_eval(Module, #elixir_scope{} = S) ->
2727
scope_for_eval(Module, Opts) ->
2828
scope_for_eval(Module, elixir:scope_for_eval(Opts)).
2929

30-
binding_for_eval(Module, Binding) -> [{'_@MODULE',Module}|Binding].
31-
3230
%% TABLE METHODS
3331

3432
data_table(Module) ->
@@ -247,7 +245,7 @@ spec_for_macro(Else) -> Else.
247245
%% Loads the form into the code server.
248246

249247
load_form(Line, Forms, S) ->
250-
elixir_compiler:module(Forms, S, fun(Module, Binary) ->
248+
elixir_compiler:module(Forms, S#elixir_scope.file, fun(Module, Binary) ->
251249
EvalS = scope_for_eval(Module, S),
252250
Env = elixir_scope:to_ex_env({ Line, EvalS }),
253251
eval_callbacks(Line, Module, after_compile, [Env, Binary], EvalS),
@@ -332,8 +330,9 @@ else_clause() ->
332330

333331
% HELPERS
334332

335-
eval_callbacks(Line, Module, Name, Args, S) ->
336-
Binding = binding_for_eval(Module, []),
333+
eval_callbacks(Line, Module, Name, Args, RawS) ->
334+
Binding = elixir_scope:binding_for_eval([], Module),
335+
S = elixir_scope:vars_from_binding(RawS, Binding),
337336
Callbacks = lists:reverse(ets:lookup_element(data_table(Module), Name, 2)),
338337
Meta = [{line,Line},{require,false}],
339338

lib/elixir/src/elixir_scope.erl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
serialize/1, deserialize/1,
66
serialize_with_vars/2, deserialize_with_vars/2,
77
to_erl_env/1, to_ex_env/1,
8+
vars_from_binding/2, binding_for_eval/2, binding_from_vars/2,
89
umergev/2, umergec/2, umergea/2, merge_clause_vars/2
910
]).
1011
-include("elixir.hrl").
@@ -200,3 +201,40 @@ var_merger(_Var, K1, K2) ->
200201
var_number([$@|T], _Acc) -> var_number(T, []);
201202
var_number([H|T], Acc) -> var_number(T, [H|Acc]);
202203
var_number([], Acc) -> list_to_integer(lists:reverse(Acc)).
204+
205+
%% Setup the vars in scope from binding
206+
207+
vars_from_binding(Scope, Binding) ->
208+
Scope#elixir_scope{
209+
vars=binding_dict(Binding),
210+
temp_vars=[],
211+
clause_vars=nil,
212+
counter=[]
213+
}.
214+
215+
binding_dict(List) -> binding_dict(List, orddict:new()).
216+
binding_dict([{{H,Kind},_}|T], Dict) -> binding_dict(T, orddict:store({ H, Kind }, H, Dict));
217+
binding_dict([{H,_}|T], Dict) -> binding_dict(T, orddict:store({ H, nil }, H, Dict));
218+
binding_dict([], Dict) -> Dict.
219+
220+
binding_for_eval(Binding, Module) ->
221+
Keyword = orddict:from_list(Binding),
222+
case orddict:find('_@MODULE', Keyword) of
223+
{ ok, _ } -> Keyword;
224+
_ -> orddict:store('_@MODULE', Module, Keyword)
225+
end.
226+
227+
binding_from_vars(#elixir_scope{vars=Vars}, Binding) ->
228+
binding_from_vars(Binding, [], Binding, Vars).
229+
230+
binding_from_vars([{Var,_}|T], Acc, Binding, Vars) ->
231+
case lists:member($@, atom_to_list(Var)) of
232+
true ->
233+
binding_from_vars(T, Acc, Binding, Vars);
234+
false ->
235+
RealName = orddict:fetch({ Var, nil }, Vars),
236+
RealValue = proplists:get_value(RealName, Binding, nil),
237+
binding_from_vars(T, [{Var, RealValue}|Acc], Binding, Vars)
238+
end;
239+
240+
binding_from_vars([], Acc, _Binding, _Vars) -> lists:reverse(Acc).

0 commit comments

Comments
 (0)