aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/test
diff options
context:
space:
mode:
authorJohn Högberg <[email protected]>2019-07-11 12:21:25 +0200
committerJohn Högberg <[email protected]>2019-07-11 17:41:08 +0200
commit8c0bfd12802af3265d84b8bca247529633d05fcf (patch)
treee6d7a122d2afe29c82e8b074672fe35206a409e4 /lib/compiler/test
parent3967d28c05dae77db30b15e56eb4ececf4f1afef (diff)
downloadotp-8c0bfd12802af3265d84b8bca247529633d05fcf.tar.gz
otp-8c0bfd12802af3265d84b8bca247529633d05fcf.tar.bz2
otp-8c0bfd12802af3265d84b8bca247529633d05fcf.zip
beam_validator: Values referenced by other values must be merged
This is a more proper fix for ERIERL-348. We used to think that we wouldn't need to update the type of a variable that's no longer referenced by a register ("dead value"), but the attached test case pokes a hole in that assumption. To summarize, the result of '=:='/2 is kept alive longer than one of its arguments, which gets pruned in a state merge leaving us with nothing to work on when we finally compare the result. This is fine for most operations since there's no point in (say) updating the size of a tuple we can no longer reach, but '=:='/2 updates the types of both arguments and we risk missing out on important information when either of them is gone. This commit fixes the problem by merging all values that are *reachable* from a register, rather than just those that *exist* in a register, ensuring that all values stay around at least as long as they're needed.
Diffstat (limited to 'lib/compiler/test')
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl22
1 files changed, 22 insertions, 0 deletions
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index 6b1438abdd..20f6cb2691 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -681,11 +681,16 @@ infer_on_eq_4(T) ->
%% ERIERL-348; types were inferred for dead values, causing validation to fail.
+-record(idv, {key}).
+
infer_dead_value(Config) when is_list(Config) ->
a = idv_1({a, b, c, d, e, f, g}, {0, 0, 0, 0, 0, 0, 0}),
b = idv_1({a, b, c, d, 0, 0, 0}, {a, b, c, d, 0, 0, 0}),
c = idv_1({0, 0, 0, 0, 0, f, g}, {0, 0, 0, 0, 0, f, g}),
error = idv_1(gurka, gaffel),
+
+ ok = idv_2(id(#idv{})),
+
ok.
idv_1({_A, _B, _C, _D, _E, _F, _G},
@@ -700,6 +705,23 @@ idv_1({_A, _B, _C, _D, _E, F, G},
idv_1(_A, _B) ->
error.
+%% ERL-995: The first solution to ERIERL-348 was incomplete and caused
+%% validation to fail when living values depended on delayed type inference on
+%% "dead" values.
+
+idv_2(State) ->
+ Flag = (State#idv.key == undefined),
+ case id(gurka) of
+ {_} -> id([Flag]);
+ _ -> ok
+ end,
+ if
+ Flag -> idv_called_once(State);
+ true -> ok
+ end.
+
+idv_called_once(_State) -> ok.
+
%%%-------------------------------------------------------------------------
transform_remove(Remove, Module) ->