From 351987be44e11e6eb9e5841adb197ec8e49bc49d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 6 Nov 2013 09:01:30 +0100 Subject: dialyzer,hipe,stdlib: Add Maps understanding to Dialyzer --- lib/dialyzer/src/dialyzer_cl.erl | 2 +- lib/dialyzer/src/dialyzer_dataflow.erl | 56 ++++++++++++++++++++++++++++++++-- lib/dialyzer/src/dialyzer_dep.erl | 12 ++++++++ lib/dialyzer/src/dialyzer_typesig.erl | 34 ++++++++++++++++++++- 4 files changed, 100 insertions(+), 4 deletions(-) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl index a7be6e0d05..cda801bf6c 100644 --- a/lib/dialyzer/src/dialyzer_cl.erl +++ b/lib/dialyzer/src/dialyzer_cl.erl @@ -603,7 +603,7 @@ cl_loop(State, LogCache) -> Msg = failed_anal_msg(Reason, LogCache), cl_error(State, Msg); {'EXIT', BackendPid, Reason} when Reason =/= 'normal' -> - Msg = failed_anal_msg(io_lib:format("~P", [Reason, 12]), LogCache), + Msg = failed_anal_msg(io_lib:format("~p", [Reason]), LogCache), cl_error(State, Msg); _Other -> %% io:format("Received ~p\n", [_Other]), diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index 3591d5be8e..4d614320c2 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -67,7 +67,9 @@ t_to_string/2, t_to_tlist/1, t_tuple/0, t_tuple/1, t_tuple_args/1, t_tuple_args/2, t_tuple_subtypes/2, - t_unit/0, t_unopaque/2]). + t_unit/0, t_unopaque/2, + t_map/1 + ]). %%-define(DEBUG, true). %%-define(DEBUG_PP, true). @@ -305,6 +307,12 @@ traverse(Tree, Map, State) -> handle_try(Tree, Map, State); tuple -> handle_tuple(Tree, Map, State); + map -> + handle_map(Tree, Map, State); + map_pair_assoc -> + handle_map_pair_assoc(Tree, Map, State); + map_pair_exact -> + handle_map_pair_exact(Tree, Map, State); values -> Elements = cerl:values_es(Tree), {State1, Map1, EsType} = traverse_list(Elements, Map, State), @@ -657,7 +665,8 @@ is_opaque_type_test_problem(Fun, Args, ArgTypes, State) -> FN =:= is_float; FN =:= is_function; FN =:= is_integer; FN =:= is_list; FN =:= is_number; FN =:= is_pid; FN =:= is_port; - FN =:= is_reference; FN =:= is_tuple -> + FN =:= is_reference; FN =:= is_tuple; + FN =:= is_map -> type_test_opaque_arg(Args, ArgTypes, State#state.opaques); {erlang, FN, 2} when FN =:= is_function -> type_test_opaque_arg(Args, ArgTypes, State#state.opaques); @@ -1054,6 +1063,23 @@ handle_try(Tree, Map, State) -> %%---------------------------------------- +handle_map(Tree,Map,State) -> + Pairs = cerl:map_es(Tree), + {State1, Map1, TypePairs} = traverse_list(Pairs,Map,State), + {State1, Map1, t_map(TypePairs)}. + +handle_map_pair_assoc(Tree,Map,State) -> + Elements = cerl:map_pair_assoc_es(Tree), + {State1, Map1, [K,V]} = traverse_list(Elements,Map,State), + {State1, Map1, {K,V}}. + +handle_map_pair_exact(Tree,Map,State) -> + Elements = cerl:map_pair_exact_es(Tree), + {State1, Map1, [K,V]} = traverse_list(Elements,Map,State), + {State1, Map1, {K,V}}. + +%%---------------------------------------- + handle_tuple(Tree, Map, State) -> Elements = cerl:tuple_es(Tree), {State1, Map1, EsType} = traverse_list(Elements, Map, State), @@ -1431,6 +1457,30 @@ bind_pat_vars([Pat|PatLeft], [Type|TypeLeft], Acc, Map, State, Rev) -> bind_opaque_pats(Literal, Type, Pat, Map, State, Rev); false -> {Map, Literal} end; + map -> + {Map, t_map([])}; +% Pairs = [ cerl:map_pair_es(Pair) || Pair <- cerl:map_es(Pat) ], +% MapType = t_inf(t_map([]), Type), +% case t_is_none(MapType) of +% true -> +% bind_opaque_pats(MapType, Type, Pat, Map, State, Rev); +% false -> +% MapJ = join_maps_begin(Map), +% Results = case Rev of +% true -> +% [bind_pat_vars_reverse(Pair, [t_any(),t_any()], [], MapJ, State) || Pair <- Pairs]; +% false -> +% [bind_pat_vars(Pair, [t_any(),t_any()], [], MapJ, State) || Pair <- Pairs] +% end, +% case [M || {M, _} <- Results, M =/= error] of +% [] -> bind_error([Pat], MapType, t_none(), bind); +% Maps -> +% Map1 = join_maps_end(Maps, MapJ), +% _PairTypes = [{Ktype,Vtype} || {M, [Ktype,Vtype]} <- Results, M =/= error], +% % add t_sup +% {Map1, t_map([])} +% end +% end; tuple -> Es = cerl:tuple_es(Pat), {TypedRecord, Prototype} = @@ -1641,6 +1691,8 @@ bind_guard(Guard, Map, Env, Eval, State) -> Es0 = cerl:tuple_es(Guard), {Map1, Es} = bind_guard_list(Es0, Map, Env, dont_know, State), {Map1, t_tuple(Es)}; + map -> + {Map, t_map([])}; 'let' -> Arg = cerl:let_arg(Guard), [Var] = cerl:let_vars(Guard), diff --git a/lib/dialyzer/src/dialyzer_dep.erl b/lib/dialyzer/src/dialyzer_dep.erl index 05f81399fb..12833b49c7 100644 --- a/lib/dialyzer/src/dialyzer_dep.erl +++ b/lib/dialyzer/src/dialyzer_dep.erl @@ -182,6 +182,18 @@ traverse(Tree, Out, State, CurrentFun) -> Args = cerl:tuple_es(Tree), {List, State1} = traverse_list(Args, Out, State, CurrentFun), {merge_outs(List), State1}; + map -> + Args = cerl:map_es(Tree), + {List, State1} = traverse_list(Args, Out, State, CurrentFun), + {merge_outs(List), State1}; + map_pair_assoc -> + Args = cerl:map_pair_assoc_es(Tree), + {List, State1} = traverse_list(Args, Out, State, CurrentFun), + {merge_outs(List), State1}; + map_pair_exact -> + Args = cerl:map_pair_exact_es(Tree), + {List, State1} = traverse_list(Args, Out, State, CurrentFun), + {merge_outs(List), State1}; values -> traverse_list(cerl:values_es(Tree), Out, State, CurrentFun); var -> diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl index db7875704a..4e18e9c7d2 100644 --- a/lib/dialyzer/src/dialyzer_typesig.erl +++ b/lib/dialyzer/src/dialyzer_typesig.erl @@ -55,7 +55,9 @@ t_subst/2, t_timeout/0, t_tuple/0, t_tuple/1, t_var/1, t_var_name/1, - t_none/0, t_unit/0]). + t_none/0, t_unit/0, + t_map/1 + ]). -include("dialyzer.hrl"). @@ -470,6 +472,33 @@ traverse(Tree, DefinedVars, State) -> end; [] -> {State2, TupleType} end; + map -> + {State, t_map([])}; +% Pairs = cerl:map_es(Tree), +% {State1, EVars} = traverse_list(Pairs, DefinedVars, State), +% case cerl:is_literal(cerl:fold_literal(Tree)) of +% true -> +% %% We do not need to do anything more here. +% {State, t_map([])}; +% false -> +% Fun = fun(Var, AccState) -> +% case t_has_var(Var) of +% true -> +% {AccState1, NewVar} = state__mk_var(AccState), +% {NewVar, +% state__store_conj(Var, eq, NewVar, AccState1)}; +% false -> +% {Var, AccState} +% end +% end, +% {_NewEvars, State2} = lists:mapfoldl(Fun, State1, EVars), +% {State2, t_map([])} +% end; +% map_pair_assoc -> +% [K,V] = cerl:map_pair_assoc_es(Tree), +% {State1,_} = traverse(K,DefinedVars,State), +% {State2,_} = traverse(V,DefinedVars,State), +% {_,State2}; values -> %% We can get into trouble when unifying products that have the %% same element appearing several times. Handle these cases by @@ -1037,6 +1066,9 @@ get_safe_underapprox_1([Pat|Left], Acc, Map) -> {Ts, Map1} = get_safe_underapprox_1(Es, [], Map), Type = t_tuple(Ts), get_safe_underapprox_1(Left, [Type|Acc], Map1); + map -> + %% TODO: Can maybe do something here + throw(dont_know); values -> Es = cerl:values_es(Pat), {Ts, Map1} = get_safe_underapprox_1(Es, [], Map), -- cgit v1.2.3