summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErlang/OTP <otp@erlang.org>2020-12-04 17:35:58 +0100
committerErlang/OTP <otp@erlang.org>2020-12-04 17:35:58 +0100
commit7d81561c87785966c1b053afd35d3e861649472a (patch)
tree4ad54b7e304567818e258d446ac38273e4c92ac0
parent3332c002f11c8c794aee3a94f97b19016edf1abb (diff)
parenta6fe5b8010c3c74a5c2e987e0519b0f07f39d78b (diff)
downloaderlang-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.erl22
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl23
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.