diff options
author | John Högberg <[email protected]> | 2019-06-11 14:43:53 +0200 |
---|---|---|
committer | John Högberg <[email protected]> | 2019-06-12 13:33:46 +0200 |
commit | 4411b1953bfb862aad433c2269acb82a35b0cc72 (patch) | |
tree | 047b6c4ccc98e20f7011cb288263c0e94257eb10 /lib/compiler/src/beam_validator.erl | |
parent | af617aebe254da636b7d9c2ac59e1109998b0b1c (diff) | |
download | otp-4411b1953bfb862aad433c2269acb82a35b0cc72.tar.gz otp-4411b1953bfb862aad433c2269acb82a35b0cc72.tar.bz2 otp-4411b1953bfb862aad433c2269acb82a35b0cc72.zip |
beam_validator: Subtract types when inferring type test BIFs
This is a temporary solution for basic type tests. We'll need to
handle more-or-less arbitrary values once we introduce union
types, as we need to be able to subtract on tuple_arity tests as
well.
Without this, nearly all "no_opt" test suites will fail to compile
after the validator is migrated to 'beam_types' as a result of
atom subtraction producing 'none' when all alternatives have been
exhausted.
Diffstat (limited to 'lib/compiler/src/beam_validator.erl')
-rw-r--r-- | lib/compiler/src/beam_validator.erl | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index 4c223a93ed..17e0a4fa38 100644 --- a/lib/compiler/src/beam_validator.erl +++ b/lib/compiler/src/beam_validator.erl @@ -1673,10 +1673,14 @@ infer_types_1(_) -> fun(_, S) -> S end. infer_type_test_bif(Type, Src) -> - fun({atom,true}, S) -> + fun({atom,Bool}, S) when is_boolean(Bool) -> case is_value_alive(Src, S) of - true -> update_type(fun meet/2, Type, Src, S); - false -> S + true when Bool =:= true -> + update_type(fun meet/2, Type, Src, S); + true when Bool =:= false -> + update_type(fun subtract/2, Type, Src, S); + false -> + S end; (_, S) -> S @@ -1798,6 +1802,34 @@ update_type(Merge, With, Literal, Vst) -> _Type -> Vst end. +update_ne_types(LHS, {atom,Bool}=RHS, Vst) when is_boolean(Bool) -> + %% This is a stopgap to make negative inference work for type test BIFs + %% like is_tuple. Consider the following unoptimized code: + %% + %% {call_ext,2,{extfunc,erlang,'--',2}}. + %% {bif,is_tuple,{f,0},[{x,0}],{x,1}}. + %% {test,is_eq_exact,{x,1},{f,2},{atom,false}}. + %% ... snip ... + %% {label,1}. + %% {test,is_eq_exact,{x,1},{f,1},{atom,true}}. + %% ... unreachable because {x,0} is known to be a list, so {x,1} can't + %% be true ... + %% {label,2}. + %% ... unreachable because {x,1} is neither true nor false! ... + %% + %% If we fail to determine that the first is_eq_exact never fails, our + %% state will be inconsistent after the second is_eq_exact check; we know + %% for certain that {x,0} is a list so infer_types says it can't succeed, + %% but it can't fail either because we also know that {x,1} is a boolean, + %% and the first check ruled out 'false'. + LType = get_term_type(LHS, Vst), + if + LType =:= bool -> + update_eq_types(LHS, {atom, not Bool}, Vst); + LType =/= bool -> + RType = get_term_type(RHS, Vst), + update_type(fun subtract/2, RType, LHS, Vst) + end; update_ne_types(LHS, RHS, Vst) -> %% While updating types on equality is fairly straightforward, inequality %% is a bit trickier since all we know is that the *value* of LHS differs |