Skip to content

Commit 28a66b5

Browse files
committed
Add version to case
1 parent 245066b commit 28a66b5

10 files changed

Lines changed: 51 additions & 39 deletions

File tree

lib/elixir/lib/module/types.ex

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,9 @@ defmodule Module.Types do
437437
# The mode to be used, see the @modes attribute
438438
mode: mode,
439439
# The function for handling local calls
440-
local_handler: handler
440+
local_handler: handler,
441+
# Reverse arrow handling (nil | :cache | :use)
442+
reverse_arrow: nil
441443
}
442444
end
443445

@@ -459,7 +461,9 @@ defmodule Module.Types do
459461
# Local signatures used by local handler
460462
local_sigs: %{},
461463
# Track which clauses have been used across private local calls
462-
local_used: %{}
464+
local_used: %{},
465+
# Cached reverse arrows
466+
reverse_arrows: %{}
463467
}
464468
end
465469

lib/elixir/lib/module/types/expr.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ defmodule Module.Types.Expr do
312312
end
313313

314314
def of_expr({:case, meta, [case_expr, [{:do, clauses}]]}, expected, _expr, stack, context) do
315+
_ = Keyword.fetch!(meta, :version)
315316
{case_type, context} = of_expr(case_expr, @pending, case_expr, stack, context)
316317
info = {:case, meta, case_expr, case_type}
317318

lib/elixir/src/elixir.hrl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
prematch=none,
3232
%% Stores if __STACKTRACE__ is allowed
3333
stacktrace=false,
34-
%% A map of unused vars and a version counter for vars
35-
unused={#{}, 0},
34+
%% A map of unused vars
35+
unused=#{},
3636
%% A list of modules defined in functions (runtime)
3737
runtime_modules=[],
3838
%% A tuple with maps of read and optional write current vars.
@@ -46,7 +46,9 @@
4646
%% if you write foo(a = 123), the value of `a` cannot be
4747
%% read in the following argument, only after the call
4848
%%
49-
vars={#{}, false}
49+
vars={#{}, false},
50+
%% Stores expression version counter
51+
version=0
5052
}).
5153

5254
-record(elixir_erl, {

lib/elixir/src/elixir_clauses.erl

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,14 @@ recur_cycles(Cycles, Current, Source, Seen, SkipList, Meta, Expr, E) ->
155155
%% Match
156156

157157
match(Fun, Meta, Expr, AfterS, BeforeS, #{context := nil} = E) ->
158-
#elixir_ex{vars=Current, unused={_, Counter} = Unused} = AfterS,
158+
#elixir_ex{vars=Current, unused=Unused, version=Counter} = AfterS,
159159
#elixir_ex{vars={Read, _}, prematch=Prematch} = BeforeS,
160160

161161
CallS = BeforeS#elixir_ex{
162162
prematch={Read, {#{}, []}, Counter},
163163
unused=Unused,
164-
vars=Current
164+
vars=Current,
165+
version=Counter
165166
},
166167

167168
CallE = E#{context := match},
@@ -170,15 +171,17 @@ match(Fun, Meta, Expr, AfterS, BeforeS, #{context := nil} = E) ->
170171
#elixir_ex{
171172
vars=NewCurrent,
172173
unused=NewUnused,
173-
prematch={_, Cycles, _}
174+
prematch={_, Cycles, _},
175+
version=NewCounter
174176
} = SE,
175177

176178
validate_cycles(Cycles, Meta, {match, Expr}, E),
177179

178180
EndS = AfterS#elixir_ex{
179181
prematch=Prematch,
180182
unused=NewUnused,
181-
vars=NewCurrent
183+
vars=NewCurrent,
184+
version=NewCounter
182185
},
183186

184187
EndE = EE#{context := ?key(E, context)},

lib/elixir/src/elixir_def.erl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -295,17 +295,17 @@ store_definition(CheckClauses, Kind, Meta, Name, Arity, File, Module, Defaults,
295295
%% Handling of defaults
296296

297297
unpack_defaults(Kind, Meta, Name, Args, S, E) ->
298-
{Expanded, #elixir_ex{unused={_, VersionOffset}}} = expand_defaults(Args, S, E#{context := nil}, []),
299-
unpack_expanded(Kind, Meta, Name, Expanded, VersionOffset, [], []).
298+
{Expanded, #elixir_ex{version=Counter}} = expand_defaults(Args, S, E#{context := nil}, []),
299+
unpack_expanded(Kind, Meta, Name, Expanded, Counter, [], []).
300300

301-
unpack_expanded(Kind, Meta, Name, [{'\\\\', DefaultMeta, [Expr, _]} | T] = List, VersionOffset, Acc, Clauses) ->
302-
Base = match_defaults(Acc, length(Acc) + VersionOffset, []),
303-
{Args, Invoke} = extract_defaults(List, length(Base) + VersionOffset, [], []),
301+
unpack_expanded(Kind, Meta, Name, [{'\\\\', DefaultMeta, [Expr, _]} | T] = List, Counter, Acc, Clauses) ->
302+
Base = match_defaults(Acc, length(Acc) + Counter, []),
303+
{Args, Invoke} = extract_defaults(List, length(Base) + Counter, [], []),
304304
Clause = {Meta, Base ++ Args, [], {super, [{super, {Kind, Name}}, {default, true} | DefaultMeta], Base ++ Invoke}},
305-
unpack_expanded(Kind, Meta, Name, T, VersionOffset, [Expr | Acc], [Clause | Clauses]);
306-
unpack_expanded(Kind, Meta, Name, [H | T], VersionOffset, Acc, Clauses) ->
307-
unpack_expanded(Kind, Meta, Name, T, VersionOffset, [H | Acc], Clauses);
308-
unpack_expanded(_Kind, _Meta, _Name, [], _VersionOffset, Acc, Clauses) ->
305+
unpack_expanded(Kind, Meta, Name, T, Counter, [Expr | Acc], [Clause | Clauses]);
306+
unpack_expanded(Kind, Meta, Name, [H | T], Counter, Acc, Clauses) ->
307+
unpack_expanded(Kind, Meta, Name, T, Counter, [H | Acc], Clauses);
308+
unpack_expanded(_Kind, _Meta, _Name, [], _Counter, Acc, Clauses) ->
309309
{lists:reverse(Acc), lists:reverse(Clauses)}.
310310

311311
expand_defaults([{'\\\\', Meta, [Expr, Default]} | Args], S, E, Acc) ->

lib/elixir/src/elixir_env.erl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ env_to_ex(#{context := match, versioned_vars := Vars}) ->
5656
#elixir_ex{
5757
prematch={Vars, {#{}, []}, Counter},
5858
vars={Vars, false},
59-
unused={#{}, Counter}
59+
version=Counter
6060
};
6161
env_to_ex(#{versioned_vars := Vars}) ->
6262
#elixir_ex{
6363
vars={Vars, false},
64-
unused={#{}, map_size(Vars)}
64+
version=map_size(Vars)
6565
}.
6666

6767
%% VAR HANDLING
@@ -94,10 +94,10 @@ merge_vars(V1, V2) ->
9494

9595
%% UNUSED VARS
9696

97-
reset_unused_vars(#elixir_ex{unused={_Unused, Version}} = S) ->
98-
S#elixir_ex{unused={#{}, Version}}.
97+
reset_unused_vars(#elixir_ex{} = S) ->
98+
S#elixir_ex{unused=#{}}.
9999

100-
check_unused_vars(#elixir_ex{unused={Unused, _Version}}, E) ->
100+
check_unused_vars(#elixir_ex{unused=Unused}, E) ->
101101
[elixir_errors:file_warn(calculate_span(Meta, Name), E, ?MODULE, {unused_var, Name, Overridden}) ||
102102
{{{Name, _Kind}, _Count}, {Meta, Overridden}} <- maps:to_list(Unused), is_unused_var(Name)],
103103
E.
@@ -111,10 +111,10 @@ calculate_span(Meta, Name) ->
111111
Meta
112112
end.
113113

114-
merge_and_check_unused_vars(S, #elixir_ex{vars={Read, Write}, unused={Unused, _Version}}, E) ->
115-
#elixir_ex{unused={ClauseUnused, Version}} = S,
114+
merge_and_check_unused_vars(S, #elixir_ex{vars={Read, Write}, unused=Unused}, E) ->
115+
#elixir_ex{unused=ClauseUnused} = S,
116116
NewUnused = merge_and_check_unused_vars(Read, Unused, ClauseUnused, E),
117-
S#elixir_ex{unused={NewUnused, Version}, vars={Read, Write}}.
117+
S#elixir_ex{unused=NewUnused, vars={Read, Write}}.
118118

119119
merge_and_check_unused_vars(Current, Unused, ClauseUnused, E) ->
120120
maps:fold(fun

lib/elixir/src/elixir_erl_var.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ load_pair({Pair, Value}) -> {Pair, Value}.
102102

103103
dump_binding(Binding, ErlS, ExS, PruneBefore) ->
104104
#elixir_erl{var_names=ErlVars} = ErlS,
105-
#elixir_ex{vars={ExVars, _}, unused={Unused, _}} = ExS,
105+
#elixir_ex{vars={ExVars, _}, unused=Unused} = ExS,
106106

107107
maps:fold(fun
108108
({Var, Kind} = Pair, Version, {B, V})

lib/elixir/src/elixir_expand.erl

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,8 @@ expand({'_', Meta, Kind} = Var, S, #{context := Context} = E) when is_atom(Kind)
397397
expand({Name, Meta, Kind}, S, #{context := match} = E) when is_atom(Name), is_atom(Kind) ->
398398
#elixir_ex{
399399
prematch={_, _, PrematchVersion},
400-
unused={Unused, Version},
401-
vars={Read, Write}
400+
vars={Read, Write},
401+
unused=Unused
402402
} = S,
403403

404404
Pair = {Name, elixir_utils:var_context(Meta, Kind)},
@@ -408,29 +408,31 @@ expand({Name, Meta, Kind}, S, #{context := match} = E) when is_atom(Name), is_at
408408
#{Pair := VarVersion} when VarVersion >= PrematchVersion ->
409409
maybe_warn_underscored_var_repeat(Meta, Name, Kind, E),
410410
NewUnused = var_used(Pair, Meta, VarVersion, Unused),
411-
NewWrite = (Write /= false) andalso Write#{Pair => Version},
411+
NewWrite = (Write /= false) andalso Write#{Pair => VarVersion},
412412
Var = {Name, [{version, VarVersion} | Meta], Kind},
413-
{Var, S#elixir_ex{vars={Read, NewWrite}, unused={NewUnused, Version}}, E};
413+
{Var, S#elixir_ex{vars={Read, NewWrite}, unused=NewUnused}, E};
414414

415415
%% Variable is being overridden now
416416
#{Pair := _} ->
417+
Version = S#elixir_ex.version,
417418
NewUnused = var_unused(Pair, Meta, Version, Unused, true),
418419
NewRead = Read#{Pair => Version},
419420
NewWrite = (Write /= false) andalso Write#{Pair => Version},
420421
Var = {Name, [{version, Version} | Meta], Kind},
421-
{Var, S#elixir_ex{vars={NewRead, NewWrite}, unused={NewUnused, Version + 1}}, E};
422+
{Var, S#elixir_ex{vars={NewRead, NewWrite}, unused=NewUnused, version=Version + 1}, E};
422423

423424
%% Variable defined for the first time
424425
_ ->
426+
Version = S#elixir_ex.version,
425427
NewUnused = var_unused(Pair, Meta, Version, Unused, false),
426428
NewRead = Read#{Pair => Version},
427429
NewWrite = (Write /= false) andalso Write#{Pair => Version},
428430
Var = {Name, [{version, Version} | Meta], Kind},
429-
{Var, S#elixir_ex{vars={NewRead, NewWrite}, unused={NewUnused, Version + 1}}, E}
431+
{Var, S#elixir_ex{vars={NewRead, NewWrite}, unused=NewUnused, version=Version + 1}, E}
430432
end;
431433

432434
expand({Name, Meta, Kind}, S, E) when is_atom(Name), is_atom(Kind) ->
433-
#elixir_ex{vars={Read, _Write}, unused={Unused, Version}, prematch=Prematch} = S,
435+
#elixir_ex{vars={Read, _Write}, unused=Unused, prematch=Prematch} = S,
434436
Pair = {Name, elixir_utils:var_context(Meta, Kind)},
435437

436438
Result =
@@ -471,7 +473,7 @@ expand({Name, Meta, Kind}, S, E) when is_atom(Name), is_atom(Kind) ->
471473
{ok, PairVersion} ->
472474
maybe_warn_underscored_var_access(Meta, Name, Kind, E),
473475
Var = {Name, [{version, PairVersion} | Meta], Kind},
474-
{Var, S#elixir_ex{unused={var_used(Pair, Meta, PairVersion, Unused), Version}}, E};
476+
{Var, S#elixir_ex{unused=var_used(Pair, Meta, PairVersion, Unused)}, E};
475477

476478
Error ->
477479
case lists:keyfind(if_undefined, 1, Meta) of
@@ -795,8 +797,8 @@ expand_case(Meta, Expr, Opts, S, E) ->
795797
false -> Opts
796798
end,
797799

798-
{EOpts, SO, EO} = elixir_clauses:'case'(Meta, ROpts, SE, EE),
799-
{{'case', Meta, [EExpr, EOpts]}, SO, EO}.
800+
{EOpts, #elixir_ex{version=Counter} = SO, EO} = elixir_clauses:'case'(Meta, ROpts, SE, EE),
801+
{{'case', [{version, Counter} | Meta], [EExpr, EOpts]}, SO#elixir_ex{version = Counter + 1}, EO}.
800802

801803
rewrite_case_clauses([{do, [
802804
{'->', FalseMeta, [

lib/elixir/src/elixir_module.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ maybe_prune_versioned_vars(false, _Vars, _Exs, E) ->
494494
E;
495495
maybe_prune_versioned_vars(true, Vars, ExS, E) ->
496496
PruneBefore = length(Vars),
497-
#elixir_ex{vars={ExVars, _}, unused={Unused, _}} = ExS,
497+
#elixir_ex{vars={ExVars, _}, unused=Unused} = ExS,
498498

499499
VersionedVars =
500500
maps:filter(fun

lib/elixir/test/elixir/kernel/expansion_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ defmodule Kernel.ExpansionTest do
420420
{:=, _, [var_ver(:x, 0), 0]},
421421
{:case, _, [:foo, [do: [{:->, _, [[var_ver(:x, 1)], var_ver(:x, 1)]}]]]},
422422
{:=, _, [_, var_ver(:x, 0)]},
423-
{:=, _, [var_ver(:x, 2), 2]}
423+
{:=, _, [var_ver(:x, 3), 2]}
424424
]} =
425425
expand_with_version(
426426
quote do

0 commit comments

Comments
 (0)