Skip to content

Commit 9cd5680

Browse files
author
José Valim
committed
Use a main counter for hygienic variables
1 parent 6d17b42 commit 9cd5680

File tree

6 files changed

+30
-26
lines changed

6 files changed

+30
-26
lines changed

lib/elixir/include/elixir.hrl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
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)
1514
super=false, %% when true, it means super was invoked
1615
caller=false, %% when true, it means caller was invoked
1716
module=nil, %% the current module
@@ -24,6 +23,7 @@
2423
clause_vars=nil, %% a dict of all variables defined in a particular clause
2524
extra_guards=nil, %% extra guards from args expansion
2625
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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ do_clauses(Meta, DecoupledClauses, S) ->
8383
% Transform tree just passing the variables counter forward
8484
% and storing variables defined inside each clause.
8585
Transformer = fun(X, {SAcc, CAcc, UAcc, VAcc}) ->
86-
{ TX, TS } = each_clause(Meta, X, S),
86+
{ TX, TS } = each_clause(Meta, X, SAcc),
8787
{ TX,
88-
{ elixir_scope:mergef(SAcc, TS),
88+
{ elixir_scope:mergef(S, TS),
8989
elixir_scope:merge_counters(CAcc, TS#elixir_scope.counter),
9090
ordsets:union(UAcc, TS#elixir_scope.temp_vars),
9191
[TS#elixir_scope.clause_vars|VAcc] } }

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-
counter=[{'_',length(Vars)}]
20+
hygiene_counter=length(Vars)+1
2121
}.
2222

2323
%% SCOPE MERGING

lib/elixir/src/elixir_fn.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
translate(Meta, Clauses, S) ->
77
Transformer = fun({ '->', CMeta, [ArgsWithGuards, Expr] }, Acc) ->
88
{ Args, Guards } = elixir_clauses:extract_splat_guards(ArgsWithGuards),
9-
elixir_clauses:clause(?line(CMeta), fun translate_fn_match/2, Args,
10-
Expr, Guards, elixir_scope:mergef(S, Acc))
9+
{ TClause, TS } = elixir_clauses:clause(?line(CMeta), fun translate_fn_match/2, Args, Expr, Guards, Acc),
10+
{ TClause, elixir_scope:mergef(S, TS) }
1111
end,
1212

1313
{ TClauses, NS } = lists:mapfoldl(Transformer, S, Clauses),

lib/elixir/src/elixir_scope.erl

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,19 @@ translate_var(Meta, Name, Kind, RS) when is_atom(Kind); is_integer(Kind) ->
6565
{ { var, Line, Current }, S }
6666
end.
6767

68-
build_var(Key, #elixir_scope{counter=Dict} = S) ->
69-
New = orddict:update(Key, fun(Old) -> Old + 1 end, 0, Dict),
70-
Cnt = orddict:fetch(Key, New),
68+
build_var('_', #elixir_scope{hygiene_counter=Cnt} = S) ->
69+
build_var('_', Cnt, S#elixir_scope{hygiene_counter=Cnt+1});
70+
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) ->
7175
Var =
7276
case Cnt of
73-
0 when Key /= '_' -> Key;
77+
0 -> Key;
7478
_ -> ?atom_concat([Key, "@", Cnt])
7579
end,
76-
{ Var, Cnt, S#elixir_scope{counter=New} }.
80+
{ Var, Cnt, S }.
7781

7882
warn_unsafe(Meta, Tuple, S) ->
7983
case ordsets:is_element(Tuple, S#elixir_scope.unsafe_vars) andalso
@@ -108,22 +112,24 @@ mergev(S1, S2) ->
108112
temp_vars=merge_opt_vars(T1, T2)
109113
}.
110114

111-
%% Receives two scopes and keeps the first with all
112-
%% the flags from the second.
113-
mergef(S1, S2) ->
114-
S1#elixir_scope{
115-
super=S2#elixir_scope.super,
116-
caller=S2#elixir_scope.caller
117-
}.
118-
119115
%% Receives two scopes and return the first scope with
120116
%% counters and flags from the later.
121117

122118
mergec(S1, S2) ->
123119
S1#elixir_scope{
124120
counter=S2#elixir_scope.counter,
125121
super=S2#elixir_scope.super,
126-
caller=S2#elixir_scope.caller
122+
caller=S2#elixir_scope.caller,
123+
hygiene_counter=S2#elixir_scope.hygiene_counter
124+
}.
125+
126+
%% Similar to mergec but does not merge the user vars counter.
127+
128+
mergef(S1, S2) ->
129+
S1#elixir_scope{
130+
super=S2#elixir_scope.super,
131+
caller=S2#elixir_scope.caller,
132+
hygiene_counter=S2#elixir_scope.hygiene_counter
127133
}.
128134

129135
%% Mergers.
@@ -148,12 +154,10 @@ var_merger(_Var, _K1, K2) -> K2.
148154
%% BINDINGS
149155

150156
load_binding(Binding, Scope) ->
151-
{ NewBinding, NewVars, NewCounter } = load_binding(Binding, [], [], 0),
157+
{ NewBinding, NewVars, NewCounter } = load_binding(Binding, [], [], 1),
152158
{ NewBinding, Scope#elixir_scope{
153159
vars=NewVars,
154-
match_vars=[],
155-
clause_vars=nil,
156-
counter=[{'_',NewCounter}]
160+
hygiene_counter=NewCounter
157161
} }.
158162

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

lib/elixir/src/elixir_try.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ clauses(_Meta, Clauses, S) ->
66
Catch = elixir_clauses:get_pairs('catch', Clauses),
77
Rescue = elixir_clauses:get_pairs(rescue, Clauses),
88
Transformer = fun(X, { SAcc, CAcc }) ->
9-
{ TX, TS } = each_clause(X, S),
9+
{ TX, TS } = each_clause(X, SAcc),
1010
{ TX,
11-
{ elixir_scope:mergef(SAcc, TS),
11+
{ elixir_scope:mergef(S, TS),
1212
elixir_scope:merge_counters(CAcc, TS#elixir_scope.counter) } }
1313
end,
1414
{ TClauses, { TS, TC } } =

0 commit comments

Comments
 (0)