diff options
author | Erlang/OTP <otp@erlang.org> | 2020-12-04 17:35:58 +0100 |
---|---|---|
committer | Erlang/OTP <otp@erlang.org> | 2020-12-04 17:35:58 +0100 |
commit | 7d81561c87785966c1b053afd35d3e861649472a (patch) | |
tree | 4ad54b7e304567818e258d446ac38273e4c92ac0 | |
parent | 3332c002f11c8c794aee3a94f97b19016edf1abb (diff) | |
parent | a6fe5b8010c3c74a5c2e987e0519b0f07f39d78b (diff) | |
download | erlang-7d81561c87785966c1b053afd35d3e861649472a.tar.gz |
Merge branch 'john/compiler/update-container-types/OTP-17039/ERL-1426' into maint-22
* john/compiler/update-container-types/OTP-17039/ERL-1426:
beam_validator: Update containers when extracted values change
-rw-r--r-- | lib/compiler/src/beam_validator.erl | 22 | ||||
-rw-r--r-- | lib/compiler/test/beam_validator_SUITE.erl | 23 |
2 files changed, 39 insertions, 6 deletions
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index b5617ba524..eb5df0d544 100644 --- a/lib/compiler/src/beam_validator.erl +++ b/lib/compiler/src/beam_validator.erl @@ -1800,7 +1800,7 @@ override_type(Type, Reg, Vst) -> %% This is used when linear code finds out more and more information about a %% type, so that the type gets more specialized. -update_type(Merge, With, #value_ref{}=Ref, Vst) -> +update_type(Merge, With, #value_ref{}=Ref, Vst0) -> %% If the old type can't be merged with the new one, the type information %% is inconsistent and we know that some instructions will never be %% executed at run-time. For example: @@ -1819,10 +1819,13 @@ update_type(Merge, With, #value_ref{}=Ref, Vst) -> %% We therefore throw a 'type_conflict' error instead, which causes %% validation to fail unless we're in a context where such errors can be %% handled, such as in a branch handler. - Current = get_raw_type(Ref, Vst), + Current = get_raw_type(Ref, Vst0), case Merge(Current, With) of - none -> throw({type_conflict, Current, With}); - Type -> set_type(Type, Ref, Vst) + none -> + throw({type_conflict, Current, With}); + Type -> + Vst = update_container_type(Type, Ref, Vst0), + set_type(Type, Ref, Vst) end; update_type(Merge, With, {Kind,_}=Reg, Vst) when Kind =:= x; Kind =:= y -> update_type(Merge, With, get_reg_vref(Reg, Vst), Vst); @@ -1835,6 +1838,17 @@ update_type(Merge, With, Literal, Vst) -> _Type -> Vst end. +%% Updates the container the given value was extracted from, if any. +update_container_type(Type, Ref, #vst{current=#st{vs=Vs}}=Vst) -> + case Vs of + #{ Ref := #value{op={bif,element}, + args=[{integer,Index}=Key,Tuple]} } when Index >= 1 -> + TupleType = {tuple, [Index], #{ Key => Type }}, + update_type(fun meet/2, TupleType, Tuple, Vst); + #{} -> + Vst + end. + update_ne_types(LHS, RHS, Vst0) -> %% While updating types on equality is fairly straightforward, inequality %% is a bit trickier since all we know is that the *value* of LHS differs diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl index 778a099987..7db5eec278 100644 --- a/lib/compiler/test/beam_validator_SUITE.erl +++ b/lib/compiler/test/beam_validator_SUITE.erl @@ -37,7 +37,8 @@ receive_stacked/1,aliased_types/1,type_conflict/1, infer_on_eq/1,infer_dead_value/1, receive_marker/1,safe_instructions/1, - missing_return_type/1,infer_on_ne/1]). + missing_return_type/1,infer_on_ne/1, + parent_container/1]). -include_lib("common_test/include/ct.hrl"). @@ -69,7 +70,7 @@ groups() -> receive_stacked,aliased_types,type_conflict, infer_on_eq,infer_dead_value,receive_marker, safe_instructions,missing_return_type, - infer_on_ne]}]. + infer_on_ne,parent_container]}]. init_per_suite(Config) -> test_lib:recompile(?MODULE), @@ -843,5 +844,23 @@ night(Turned) -> participating(_, _, _, _) -> ok. +%% ERL-1426: When a value was extracted from a tuple, subsequent type tests did +%% not update the type of said tuple. + +-record(pc, {a}). + +parent_container(_Config) -> + ok = pc_1(id(#pc{a=true})). + +pc_1(#pc{a=A}=R) -> + case A of + true -> ok; + false -> ok + end, + ok = pc_2(R). + +pc_2(_R) -> + ok. + id(I) -> I. |