aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src
diff options
context:
space:
mode:
authorJohn Högberg <[email protected]>2019-06-11 14:43:53 +0200
committerJohn Högberg <[email protected]>2019-06-12 13:33:46 +0200
commit4411b1953bfb862aad433c2269acb82a35b0cc72 (patch)
tree047b6c4ccc98e20f7011cb288263c0e94257eb10 /lib/compiler/src
parentaf617aebe254da636b7d9c2ac59e1109998b0b1c (diff)
downloadotp-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')
-rw-r--r--lib/compiler/src/beam_validator.erl38
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