aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2018-12-29 08:15:02 +0100
committerBjörn Gustavsson <[email protected]>2019-01-14 13:36:01 +0100
commitf548ea888e4c63546160dcb68ee84a167ca38f8f (patch)
tree7257a75df14118e1b43512373f3579b64a77f5a7 /lib/compiler
parentfb90ee4a0aab48dca08e9c935b26c4742d4c86ab (diff)
downloadotp-f548ea888e4c63546160dcb68ee84a167ca38f8f.tar.gz
otp-f548ea888e4c63546160dcb68ee84a167ca38f8f.tar.bz2
otp-f548ea888e4c63546160dcb68ee84a167ca38f8f.zip
Infer types from more BIFs
Diffstat (limited to 'lib/compiler')
-rw-r--r--lib/compiler/src/beam_ssa_type.erl36
-rw-r--r--lib/compiler/src/beam_validator.erl25
2 files changed, 61 insertions, 0 deletions
diff --git a/lib/compiler/src/beam_ssa_type.erl b/lib/compiler/src/beam_ssa_type.erl
index 95fc3bb0e9..118f4d57bc 100644
--- a/lib/compiler/src/beam_ssa_type.erl
+++ b/lib/compiler/src/beam_ssa_type.erl
@@ -542,6 +542,14 @@ type(call, [#b_remote{mod=#b_literal{val=Mod},
{_,_} ->
#t_tuple{}
end;
+ {erlang,'++',[List1,List2]} ->
+ case get_type(List1, Ts) =:= cons orelse
+ get_type(List2, Ts) =:= cons of
+ true -> cons;
+ false -> list
+ end;
+ {erlang,'--',[_,_]} ->
+ list;
{math,_,_} ->
case is_math_bif(Name, length(Args)) of
false -> any;
@@ -885,6 +893,8 @@ infer_type({bif,element}, [#b_literal{val=Pos},#b_var{}=Tuple], _Ds) ->
true ->
[]
end;
+infer_type({bif,element}, [#b_var{}=Position,#b_var{}=Tuple], _Ds) ->
+ [{Position,t_integer()},{Tuple,#t_tuple{}}];
infer_type({bif,'=:='}, [#b_var{}=Src,#b_literal{}=Lit], Ds) ->
Def = maps:get(Src, Ds),
Type = get_type(Lit, #{}),
@@ -895,10 +905,20 @@ infer_type({bif,Bif}, [#b_var{}=Src]=Args, _Ds) ->
any -> [];
T -> [{Src,T}]
end;
+infer_type({bif,binary_part}, [#b_var{}=Src,_], _Ds) ->
+ [{Src,{binary,8}}];
infer_type({bif,is_map_key}, [_,#b_var{}=Src], _Ds) ->
[{Src,map}];
infer_type({bif,map_get}, [_,#b_var{}=Src], _Ds) ->
[{Src,map}];
+infer_type({bif,Bif}, [_,_]=Args, _Ds) ->
+ case inferred_bif_type(Bif, Args) of
+ any -> [];
+ T -> [{A,T} || #b_var{}=A <- Args]
+ end;
+infer_type({bif,binary_part}, [#b_var{}=Src,Pos,Len], _Ds) ->
+ [{Src,{binary,8}}|
+ [{V,t_integer()} || #b_var{}=V <- [Pos,Len]]];
infer_type(bs_start_match, [#b_var{}=Bin], _Ds) ->
[{Bin,{binary,1}}];
infer_type(is_nonempty_list, [#b_var{}=Src], _Ds) ->
@@ -969,6 +989,7 @@ inferred_bif_type(is_number, [_]) -> number;
inferred_bif_type(is_tuple, [_]) -> #t_tuple{};
inferred_bif_type(abs, [_]) -> number;
inferred_bif_type(bit_size, [_]) -> {binary,1};
+inferred_bif_type('bnot', [_]) -> t_integer();
inferred_bif_type(byte_size, [_]) -> {binary,1};
inferred_bif_type(ceil, [_]) -> number;
inferred_bif_type(float, [_]) -> number;
@@ -976,10 +997,25 @@ inferred_bif_type(floor, [_]) -> number;
inferred_bif_type(hd, [_]) -> cons;
inferred_bif_type(length, [_]) -> list;
inferred_bif_type(map_size, [_]) -> map;
+inferred_bif_type('not', [_]) -> t_boolean();
inferred_bif_type(round, [_]) -> number;
inferred_bif_type(trunc, [_]) -> number;
inferred_bif_type(tl, [_]) -> cons;
inferred_bif_type(tuple_size, [_]) -> #t_tuple{};
+inferred_bif_type('and', [_,_]) -> t_boolean();
+inferred_bif_type('or', [_,_]) -> t_boolean();
+inferred_bif_type('xor', [_,_]) -> t_boolean();
+inferred_bif_type('band', [_,_]) -> t_integer();
+inferred_bif_type('bor', [_,_]) -> t_integer();
+inferred_bif_type('bsl', [_,_]) -> t_integer();
+inferred_bif_type('bsr', [_,_]) -> t_integer();
+inferred_bif_type('bxor', [_,_]) -> t_integer();
+inferred_bif_type('div', [_,_]) -> t_integer();
+inferred_bif_type('rem', [_,_]) -> t_integer();
+inferred_bif_type('+', [_,_]) -> number;
+inferred_bif_type('-', [_,_]) -> number;
+inferred_bif_type('*', [_,_]) -> number;
+inferred_bif_type('/', [_,_]) -> number;
inferred_bif_type(_, _) -> any.
infer_tuple_size(#b_set{op={bif,tuple_size},args=[#b_var{}=Tuple]},
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index d01013101a..46c689e034 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -809,6 +809,14 @@ valfun_4({test,has_map_fields,{f,Lbl},Src,{list,List}}, Vst) ->
assert_type(map, Src, Vst),
assert_unique_map_keys(List),
branch_state(Lbl, Vst);
+valfun_4({test,is_list,{f,Lbl},[Src]}, Vst) ->
+ validate_src([Src], Vst),
+ Type = case get_term_type(Src, Vst) of
+ cons -> cons;
+ nil -> nil;
+ _ -> list
+ end,
+ set_aliased_type(Type, Src, branch_state(Lbl, Vst));
valfun_4({test,is_map,{f,Lbl},[Src]}, Vst0) ->
Vst = branch_state(Lbl, Vst0),
case Src of
@@ -820,6 +828,13 @@ valfun_4({test,is_map,{f,Lbl},[Src]}, Vst0) ->
_ ->
kill_state(Vst0)
end;
+valfun_4({test,is_nil,{f,Lbl},[Src]}, Vst) ->
+ case get_term_type(Src, Vst) of
+ list ->
+ branch_state(Lbl, set_type_reg(cons, Src, Vst));
+ _ ->
+ branch_state(Lbl, Vst)
+ end;
valfun_4({test,is_eq_exact,{f,Lbl},[Src,Val]=Ss}, Vst0) ->
validate_src(Ss, Vst0),
Infer = infer_types(Src, Vst0),
@@ -1536,6 +1551,8 @@ assert_not_literal(Literal) -> error({literal_not_allowed,Literal}).
%%
%% nil Empty list: []
%%
+%% list List: [] or [_|_]
+%%
%% {tuple,[Sz]} Tuple. An element has been accessed using
%% element/2 or setelement/3 so that it is known that
%% the type is a tuple of size at least Sz.
@@ -2118,6 +2135,14 @@ return_type_1(erlang, setelement, 3, Vst) ->
{integer,I} -> upgrade_tuple_type({tuple,[I]}, TupleType);
_ -> TupleType
end;
+return_type_1(erlang, '++', 2, Vst) ->
+ case get_term_type({x,0}, Vst) =:= cons orelse
+ get_term_type({x,1}, Vst) =:= cons of
+ true -> cons;
+ false -> list
+ end;
+return_type_1(erlang, '--', 2, _Vst) ->
+ list;
return_type_1(erlang, F, A, _) ->
return_type_erl(F, A);
return_type_1(math, F, A, _) ->