Skip to content

Commit 1c4b759

Browse files
author
José Valim
committed
Bring back no name and simplify var merging
1 parent f670222 commit 1c4b759

File tree

6 files changed

+30
-65
lines changed

6 files changed

+30
-65
lines changed

lib/elixir/include/elixir.hrl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
-record(elixir_scope, {
1212
context=nil, %% can be assign, guards or nil
1313
extra=nil, %% extra information about the context, like fn_match and do_match
14+
noname=false, %% when true, don't add new names (used by try)
1415
super=false, %% when true, it means super was invoked
1516
caller=false, %% when true, it means caller was invoked
1617
module=nil, %% the current module
@@ -23,7 +24,6 @@
2324
clause_vars=nil, %% a dict of all variables defined in a particular clause
2425
extra_guards=nil, %% extra guards from args expansion
2526
counter=[], %% a dict counting the variables defined
26-
hygiene_counter=1, %% a counter for the hygienic vars (start with underscore)
2727
file=(<<"nofile">>) %% the current scope filename
2828
}).
2929

lib/elixir/src/elixir_clauses.erl

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,16 @@ do_clauses(_Meta, [], S) ->
8282
do_clauses(Meta, DecoupledClauses, S) ->
8383
% Transform tree just passing the variables counter forward
8484
% and storing variables defined inside each clause.
85-
Transformer = fun(X, {SAcc, CAcc, UAcc, VAcc}) ->
85+
Transformer = fun(X, {SAcc, UAcc, VAcc}) ->
8686
{ TX, TS } = each_clause(Meta, X, SAcc),
8787
{ TX,
88-
{ elixir_scope:mergef(S, TS),
89-
elixir_scope:merge_counters(CAcc, TS#elixir_scope.counter),
88+
{ elixir_scope:mergec(S, TS),
9089
ordsets:union(UAcc, TS#elixir_scope.temp_vars),
9190
[TS#elixir_scope.clause_vars|VAcc] } }
9291
end,
9392

94-
{ TClauses, { TS, Counter, Unsafe, ReverseCV } } =
95-
lists:mapfoldl(Transformer, {S, S#elixir_scope.counter, S#elixir_scope.unsafe_vars, []}, DecoupledClauses),
93+
{ TClauses, { TS, Unsafe, ReverseCV } } =
94+
lists:mapfoldl(Transformer, {S, S#elixir_scope.unsafe_vars, []}, DecoupledClauses),
9695

9796
% Now get all the variables defined inside each clause
9897
CV = lists:reverse(ReverseCV),
@@ -105,7 +104,7 @@ do_clauses(Meta, DecoupledClauses, S) ->
105104
% is the old pointer.
106105
{ FinalVars, FS } = lists:mapfoldl(fun({ Key, Val }, Acc) ->
107106
normalize_vars(Key, Val, Acc)
108-
end, TS#elixir_scope{unsafe_vars=Unsafe, counter=Counter}, AllVars),
107+
end, TS#elixir_scope{unsafe_vars=Unsafe}, AllVars),
109108

110109
% Expand all clauses by adding a match operation at the end
111110
% that defines variables missing in one clause to the others.
@@ -174,54 +173,36 @@ each_clause(_PMeta, { 'after', Meta, [Condition], Expr }, S) ->
174173

175174
has_match_tuple({'receive', _, _, _, _}) ->
176175
true;
177-
178176
has_match_tuple({'receive', _, _}) ->
179177
true;
180-
181178
has_match_tuple({'case', _, _, _}) ->
182179
true;
183-
184180
has_match_tuple({match, _, _, _}) ->
185181
true;
186-
187182
has_match_tuple({'fun', _, { clauses, _ }}) ->
188183
false;
189-
190184
has_match_tuple(H) when is_tuple(H) ->
191185
has_match_tuple(tuple_to_list(H));
192-
193186
has_match_tuple(H) when is_list(H) ->
194187
lists:any(fun has_match_tuple/1, H);
195-
196188
has_match_tuple(_) -> false.
197189

198190
% Normalize the given var in between clauses
199191
% by picking one value as reference and retriving
200192
% its previous value.
201-
%
202-
% If the variable starts with _, we cannot reuse it
203-
% since those shared variables will likely clash.
204-
205-
normalize_vars(Key, { OldValue, OldCounter }, #elixir_scope{vars=Vars,clause_vars=ClauseVars} = S) ->
206-
{ Value, Counter, CS } =
207-
case atom_to_list(OldValue) of
208-
"_" ++ _ -> elixir_scope:build_var('_', S);
209-
_ -> { OldValue, OldCounter, S }
210-
end,
211-
212-
Tuple = { Value, Counter },
213-
214-
VS = CS#elixir_scope{
215-
vars=orddict:store(Key, Tuple, Vars),
216-
clause_vars=orddict:store(Key, Tuple, ClauseVars)
193+
194+
normalize_vars(Key, Value, #elixir_scope{vars=Vars,clause_vars=ClauseVars} = S) ->
195+
VS = S#elixir_scope{
196+
vars=orddict:store(Key, Value, Vars),
197+
clause_vars=orddict:store(Key, Value, ClauseVars)
217198
},
218199

219200
Expr = case orddict:find(Key, Vars) of
220201
{ ok, { PreValue, _ } } -> { var, 0, PreValue };
221202
error -> { atom, 0, nil }
222203
end,
223204

224-
{ { Key, Tuple, Expr }, VS }.
205+
{ { Key, Value, Expr }, VS }.
225206

226207
% Generate match vars by checking if they were updated
227208
% or not and assigning the previous value.

lib/elixir/src/elixir_env.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ env_to_scope(#elixir_env{module=Module,file=File,function=Function,context=Conte
1717
env_to_scope_with_vars(#elixir_env{} = Env, Vars) ->
1818
(env_to_scope(Env))#elixir_scope{
1919
vars=orddict:from_list(Vars),
20-
hygiene_counter=length(Vars)+1
20+
counter=[{'_',length(Vars)}]
2121
}.
2222

2323
%% SCOPE MERGING

lib/elixir/src/elixir_scope.erl

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
load_binding/2, dump_binding/2,
55
format_error/1, warn_unsafe/3,
66
mergev/2, mergec/2, mergef/2,
7-
merge_vars/2, merge_opt_vars/2, merge_counters/2
7+
merge_vars/2, merge_opt_vars/2
88
]).
99
-include("elixir.hrl").
1010

@@ -47,7 +47,8 @@ translate_var(Meta, Name, Kind, RS) when is_atom(Kind); is_integer(Kind) ->
4747
{ NewVar, Counter, NS } =
4848
if
4949
Kind /= nil -> build_var('_', S);
50-
true -> build_var(Name, S)
50+
Exists orelse S#elixir_scope.noname -> build_var(Name, S);
51+
true -> { Name, 0, S }
5152
end,
5253

5354
FS = NS#elixir_scope{
@@ -65,19 +66,10 @@ translate_var(Meta, Name, Kind, RS) when is_atom(Kind); is_integer(Kind) ->
6566
{ { var, Line, Current }, S }
6667
end.
6768

68-
build_var('_', #elixir_scope{hygiene_counter=Cnt} = S) ->
69-
build_var('_', Cnt, S#elixir_scope{hygiene_counter=Cnt+1});
7069
build_var(Key, S) ->
71-
New = orddict:update(Key, fun(Old) -> Old + 1 end, 0, S#elixir_scope.counter),
72-
build_var(Key, orddict:fetch(Key, New), S#elixir_scope{counter=New}).
73-
74-
build_var(Key, Cnt, S) ->
75-
Var =
76-
case Cnt of
77-
0 -> Key;
78-
_ -> ?atom_concat([Key, "@", Cnt])
79-
end,
80-
{ Var, Cnt, S }.
70+
New = orddict:update_counter(Key, 1, S#elixir_scope.counter),
71+
Cnt = orddict:fetch(Key, New),
72+
{ ?atom_concat([Key, "@", Cnt]), Cnt, S#elixir_scope{counter=New} }.
8173

8274
warn_unsafe(Meta, Tuple, S) ->
8375
case ordsets:is_element(Tuple, S#elixir_scope.unsafe_vars) andalso
@@ -119,25 +111,19 @@ mergec(S1, S2) ->
119111
S1#elixir_scope{
120112
counter=S2#elixir_scope.counter,
121113
super=S2#elixir_scope.super,
122-
caller=S2#elixir_scope.caller,
123-
hygiene_counter=S2#elixir_scope.hygiene_counter
114+
caller=S2#elixir_scope.caller
124115
}.
125116

126117
%% Similar to mergec but does not merge the user vars counter.
127118

128119
mergef(S1, S2) ->
129120
S1#elixir_scope{
130121
super=S2#elixir_scope.super,
131-
caller=S2#elixir_scope.caller,
132-
hygiene_counter=S2#elixir_scope.hygiene_counter
122+
caller=S2#elixir_scope.caller
133123
}.
134124

135125
%% Mergers.
136126

137-
merge_counters(C, C) -> C;
138-
merge_counters(C1, C2) ->
139-
orddict:merge(fun(_K, V1, V2) -> max(V1, V2) end, C1, C2).
140-
141127
merge_vars(V, V) -> V;
142128
merge_vars(V1, V2) ->
143129
orddict:merge(fun var_merger/3, V1, V2).
@@ -154,10 +140,10 @@ var_merger(_Var, _K1, K2) -> K2.
154140
%% BINDINGS
155141

156142
load_binding(Binding, Scope) ->
157-
{ NewBinding, NewVars, NewCounter } = load_binding(Binding, [], [], 1),
143+
{ NewBinding, NewVars, NewCounter } = load_binding(Binding, [], [], 0),
158144
{ NewBinding, Scope#elixir_scope{
159145
vars=NewVars,
160-
hygiene_counter=NewCounter
146+
counter=[{'_',NewCounter}]
161147
} }.
162148

163149
load_binding([{Key,Value}|T], Binding, Vars, Counter) ->

lib/elixir/src/elixir_translator.erl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ translate({'case', Meta, [Expr, KV]}, S) when is_list(KV) ->
7878

7979
%% Try
8080

81-
translate({'try', Meta, [Clauses]}, S) when is_list(Clauses) ->
81+
translate({'try', Meta, [Clauses]}, RS) when is_list(Clauses) ->
82+
S = RS#elixir_scope{noname=true},
8283
Do = proplists:get_value('do', Clauses, nil),
8384
{ TDo, SB } = elixir_translator:translate(Do, S),
8485

@@ -91,7 +92,8 @@ translate({'try', Meta, [Clauses]}, S) when is_list(Clauses) ->
9192
Else = elixir_clauses:get_pairs(else, Clauses),
9293
{ TElse, SE } = elixir_clauses:clauses(Meta, Else, mergec(S, SA)),
9394

94-
{ { 'try', ?line(Meta), unblock(TDo), TElse, TCatch, unblock(TAfter) }, mergec(S, SE) };
95+
SF = (mergec(S, SE))#elixir_scope{noname=RS#elixir_scope.noname},
96+
{ { 'try', ?line(Meta), unblock(TDo), TElse, TCatch, unblock(TAfter) }, SF };
9597

9698
%% Receive
9799

lib/elixir/src/elixir_try.erl

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,11 @@
55
clauses(_Meta, Clauses, S) ->
66
Catch = elixir_clauses:get_pairs('catch', Clauses),
77
Rescue = elixir_clauses:get_pairs(rescue, Clauses),
8-
Transformer = fun(X, { SAcc, CAcc }) ->
8+
Transformer = fun(X, SAcc) ->
99
{ TX, TS } = each_clause(X, SAcc),
10-
{ TX,
11-
{ elixir_scope:mergef(S, TS),
12-
elixir_scope:merge_counters(CAcc, TS#elixir_scope.counter) } }
10+
{ TX, elixir_scope:mergec(S, TS) }
1311
end,
14-
{ TClauses, { TS, TC } } =
15-
lists:mapfoldl(Transformer, { S, S#elixir_scope.counter }, Rescue ++ Catch),
16-
{ TClauses, TS#elixir_scope{counter=TC} }.
12+
lists:mapfoldl(Transformer, S, Rescue ++ Catch).
1713

1814
each_clause({ 'catch', Meta, Raw, Expr }, S) ->
1915
{ Args, Guards } = elixir_clauses:extract_splat_guards(Raw),

0 commit comments

Comments
 (0)