summaryrefslogtreecommitdiff
path: root/lib/compiler/src/beam_validator.erl
diff options
context:
space:
mode:
authorJohn Högberg <john@erlang.org>2020-03-31 09:58:42 +0200
committerJohn Högberg <john@erlang.org>2020-03-31 10:14:18 +0200
commit5023585a5326c60ae4396f7fbb4c47364852a2ee (patch)
tree5f91b2ca205e075e29c61884f90c0cad00ffe52b /lib/compiler/src/beam_validator.erl
parent5b526169ea616e87a7145d2a996b94a91879f200 (diff)
downloaderlang-5023585a5326c60ae4396f7fbb4c47364852a2ee.tar.gz
beam_validator: Improve type inference for '=/='
Diffstat (limited to 'lib/compiler/src/beam_validator.erl')
-rw-r--r--lib/compiler/src/beam_validator.erl34
1 files changed, 25 insertions, 9 deletions
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 72b41c6d3d..b5617ba524 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -1667,11 +1667,16 @@ infer_types(_, #vst{}) ->
infer_types_1(#value{op={bif,'=:='},args=[LHS,RHS]}) ->
fun({atom,true}, S) ->
- %% Either side might contain something worth inferring, so we need
- %% to check them both.
- Infer_L = infer_types(RHS, S),
- Infer_R = infer_types(LHS, S),
- Infer_R(RHS, Infer_L(LHS, S));
+ update_eq_types(LHS, RHS, S);
+ ({atom,false}, S) ->
+ update_ne_types(LHS, RHS, S);
+ (_, S) -> S
+ end;
+infer_types_1(#value{op={bif,'=/='},args=[LHS,RHS]}) ->
+ fun({atom,true}, S) ->
+ update_ne_types(LHS, RHS, S);
+ ({atom,false}, S) ->
+ update_eq_types(LHS, RHS, S);
(_, S) -> S
end;
infer_types_1(#value{op={bif,element},args=[{integer,Index}=Key,Tuple]}) ->
@@ -1830,7 +1835,7 @@ update_type(Merge, With, Literal, Vst) ->
_Type -> Vst
end.
-update_ne_types(LHS, RHS, Vst) ->
+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
%% from RHS, so we can't blindly subtract their types.
@@ -1840,10 +1845,21 @@ update_ne_types(LHS, RHS, Vst) ->
%% {integer,[]} we would erroneously infer that the new type is {float,[]}.
%%
%% Therefore, we only subtract when we know that RHS has a specific value.
- RType = get_term_type(RHS, Vst),
+ RType = get_term_type(RHS, Vst0),
case is_literal(RType) of
- true -> update_type(fun subtract/2, RType, LHS, Vst);
- false -> Vst
+ true ->
+ Vst = update_type(fun subtract/2, RType, LHS, Vst0),
+
+ %% If LHS has a specific value after subtraction we can infer types
+ %% as if we've made an exact match, which is much stronger than
+ %% ne_exact.
+ LType = get_term_type(LHS, Vst),
+ case is_literal(LType) of
+ true -> update_eq_types(LHS, LType, Vst);
+ false -> Vst
+ end;
+ false ->
+ Vst0
end.
update_eq_types(LHS, RHS, Vst0) ->