dialyzer_dataflow.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 2,097 行 · 第 1/5 页

ERL
2,097
字号
		end,	      case ((t_is_atom(true, Bool1) andalso t_is_bool(Bool2))		    orelse 		    (t_is_atom(true, Bool2) andalso t_is_bool(Bool1))) of		true -> {join_maps([Map1, Map2], Map), t_from_term(true)};		false -> throw({fail, none})	      end;	    neg ->	      {Map1, Type1} = bind_guard(Arg1, Map, Env, neg, State),	      case t_is_atom(true, Type1) of		false -> throw({fail, none});		true ->		  {Map2, Type2} = bind_guard(Arg2, Map1, Env, neg, State),		  case t_is_atom(true, Type2) of		    false -> throw({fail, none});		    true -> {Map2, t_atom(false)}		  end	      end;	    dont_know ->	      {Map1, Bool1} = bind_guard(Arg1, Map, Env, dont_know, State),	      {Map2, Bool2} = bind_guard(Arg2, Map, Env, dont_know, State),	      case t_is_bool(Bool1) andalso t_is_bool(Bool2) of		true -> {join_maps([Map1, Map2], Map), t_sup(Bool1, Bool2)};		false -> throw({fail, none})	      end	  end;	{erlang, 'not', 1} ->	  [Arg] = Args,	  case Eval of	    neg -> 	      {Map1, Type} = bind_guard(Arg, Map, Env, pos, State),	      case t_is_atom(true, Type) of		true -> {Map1, t_atom(false)};		false -> throw({fail, none})	      end;	    pos -> 	      {Map1, Type} = bind_guard(Arg, Map, Env, neg, State),	      case t_is_atom(false, Type) of		true -> {Map1, t_atom(true)};		false -> throw({fail, none})	      end;	    dont_know -> 	      {Map1, Type} = bind_guard(Arg, Map, Env, dont_know, State),	      Bool = t_inf(Type, t_bool()),	      case t_is_none(Bool) of		true -> throw({fatal_fail, none});		false ->		  case t_atom_vals(Type) of		    [true] -> {Map1, t_from_term(false)};		    [false] -> {Map1, t_from_term(true)};		    [_, _] -> {Map1, Type}		  end	      end	  end;	{M, F, A} ->	  {Map1, As} = bind_guard_list(Args, Map, Env, dont_know, State),	  BifRet = erl_bif_types:type(M, F, A, As),	  case t_is_none(BifRet) of	    true ->	      %% Is this an error-bif?	      case t_is_none(erl_bif_types:type(M, F, A)) of		true -> signal_guard_fail(Guard, As, State);		false -> signal_guard_fatal_fail(Guard, As, State)	      end;	    false ->	      case erl_bif_types:arg_types(M, F, A) of		any -> BifArgs = duplicate(A, t_any());		List -> BifArgs = List	      end,	      Map2 = enter_type_lists(Args, t_inf_lists(BifArgs, As), Map1),	      Ret = 		case Eval of		  pos -> t_inf(t_from_term(true), BifRet);		  neg -> t_inf(t_from_term(false), BifRet);		  dont_know -> BifRet		end,	      case t_is_none(Ret) of		true ->		  case Eval =:= pos of		    true -> signal_guard_fail(Guard, As, State);		    false -> throw({fail, none})		  end;		false -> {Map2, Ret}	      end	  end      end  end.bind_type_test(Eval, TypeTest, ArgType) ->  Type = case TypeTest of	   is_atom -> t_atom();	   is_boolean -> t_bool();	   is_binary -> t_binary();	   is_float -> t_float();	   is_function -> t_fun();	   is_integer -> t_integer();	   is_list -> t_pos_improper_list();	   is_number -> t_number();	   is_pid -> t_pid();	   is_port -> t_port();	   is_reference -> t_ref();	   is_tuple -> t_tuple()	 end,  case Eval of    pos ->      Inf = t_inf(Type, ArgType),      case t_is_none(Inf) of	true -> error;	false -> {ok, Inf, t_from_term(true)}      end;    neg ->      Sub = t_subtract(ArgType, Type),      case t_is_none(Sub) of	true -> error;	false -> {ok, Sub, t_from_term(false)}      end;    dont_know ->      {ok, ArgType, t_bool()}  end.bind_eq_guard(Guard, Arg1, Arg2, Map, Env, Eval, State) ->  {Map1, Type1} = bind_guard(Arg1, Map, Env, dont_know, State),  {Map2, Type2} = bind_guard(Arg2, Map1, Env, dont_know, State),  case (t_is_nil(Type1) orelse t_is_nil(Type2) orelse	t_is_atom(Type1) orelse t_is_atom(Type2)) of    true -> bind_eqeq_guard(Guard, Arg1, Arg2, Map, Env, Eval, State);    false ->      case Eval of	pos -> {Map2, t_from_term(true)};	neg -> {Map2, t_from_term(false)};	dont_know -> {Map2, t_bool()}      end  end.bind_eqeq_guard(Guard, Arg1, Arg2, Map, Env, Eval, State) ->  {Map1, Type1} = bind_guard(Arg1, Map, Env, dont_know, State),  {Map2, Type2} = bind_guard(Arg2, Map1, Env, dont_know, State),  ?debug("Types are:~s =:= ~s\n", [t_to_string(Type1), 				   t_to_string(Type2)]),  Inf = t_inf(Type1, Type2),  case t_is_none(Inf) of    true ->      case Eval of	neg -> {Map2, t_from_term(false)};	dont_know -> {Map2, t_from_term(false)};	pos -> signal_guard_fail(Guard, [Type1, Type2], State)      end;    false ->      case Eval of	pos ->	  case {cerl:type(Arg1), cerl:type(Arg2)} of	    {var, var} ->	      Map3 = enter_subst(Arg1, Arg2, Map2),	      Map4 = enter_type(Arg2, Inf, Map3),	      {Map4, t_atom(true)};	    {var, _} ->	      Map3 = enter_type(Arg1, Inf, Map2),	      {Map3, t_atom(true)};	    {_, var} ->	      Map3 = enter_type(Arg2, Inf, Map2),	      {Map3, t_atom(true)};	    {_, _} ->	      {Map2, t_atom(true)}	  end;	neg ->	  {Map2, t_from_term(false)};	dont_know ->	  {Map2, t_bool()}      end  end.bind_eqeq_guard_lit_other(Guard, Arg1, Arg2, Map, Env, State) ->  %% Assumes positive evaluation  case cerl:concrete(Arg1) of    true ->      {Map1, Type} = bind_guard(Arg2, Map, Env, pos, State),      case t_is_atom(true, Type) of	true -> {Map1, Type};	false -> 	  {_, Type0} = bind_guard(Arg2, Map, Env, dont_know, State),	  signal_guard_fail(Guard, [Type0, t_from_term(true)], State)      end;    false ->       {Map1, Type} = bind_guard(Arg2, Map, Env, neg, State),      case t_is_atom(false, Type) of	true -> {Map1, t_atom(true)};	false -> 	  {_, Type0} = bind_guard(Arg2, Map, Env, dont_know, State),	  signal_guard_fail(Guard, [Type0, t_from_term(true)], State)      end;    Term ->      LitType = t_from_term(Term),      {Map1, Type} = bind_guard(Arg2, Map, Env, dont_know, State),      case t_is_subtype(LitType, Type) of	false -> signal_guard_fail(Guard, [Type, LitType], State);	true ->	  case cerl:is_c_var(Arg2) of	    true -> {enter_type(Arg2, LitType, Map1), t_from_term(true)};	    false -> {Map1, t_from_term(true)}	  end      end  end.bind_guard_list(Guards, Map, Env, Eval, State) ->  bind_guard_list(Guards, Map, Env, Eval, State, []).bind_guard_list([G|Left], Map, Env, Eval, State, Acc) ->  {Map1, T} = bind_guard(G, Map, Env, Eval, State),  bind_guard_list(Left, Map1, Env, Eval, State, [T|Acc]);bind_guard_list([], Map, _Env, _Eval, _State, Acc) ->  {Map, lists:reverse(Acc)}.signal_guard_fail(Guard, ArgTypes, State) ->  Args = cerl:call_args(Guard),  F = cerl:atom_val(cerl:call_name(Guard)),  MFA = {cerl:atom_val(cerl:call_module(Guard)), F, length(Args)},  Msg =    case is_infix_op(MFA) of      true -> 	[ArgType1, ArgType2] = ArgTypes,	[Arg1, Arg2] = Args,	io_lib:format("Guard test ~s ~s ~s can never succeed.\n",		      [format_args_1([Arg1], [ArgType1], State), 		       atom_to_list(F),		       format_args_1([Arg2], [ArgType2], State)]);      false ->	io_lib:format("Guard test ~w~s can never succeed\n", 		      [F, format_args(Args, ArgTypes, State)])    end,  throw({fail, {Guard, Msg}}).is_infix_op({erlang, '=:=', 2}) -> true;is_infix_op({erlang, '==', 2}) -> true;is_infix_op({erlang, '=/=', 2}) -> true;is_infix_op({erlang, '=/', 2}) -> true;is_infix_op({erlang, '<', 2}) -> true;is_infix_op({erlang, '=<', 2}) -> true;is_infix_op({erlang, '>', 2}) -> true;is_infix_op({erlang, '>=', 2}) -> true;is_infix_op({_, _, _}) -> false.signal_guard_fatal_fail(Guard, ArgTypes, State) ->  Args = cerl:call_args(Guard),        F = cerl:atom_val(cerl:call_name(Guard)),  Msg = io_lib:format("Guard test ~w~s can never succeed\n",		      [F, format_args(Args, ArgTypes, State)]),  throw({fatal_fail, {Guard, Msg}}).bind_guard_case_clauses(Arg, Clauses, Map, Env, Eval, State) ->  Clauses1 = filter_fail_clauses(Clauses),  {GenMap, GenArgType} = bind_guard(Arg, Map, Env, dont_know, State),  bind_guard_case_clauses(GenArgType, GenMap, Arg, Clauses1, Map, Env, Eval, 			  t_none(), [], State).filter_fail_clauses([Clause|Left]) ->  case (cerl:clause_pats(Clause) =:= []) of    true ->      Body = cerl:clause_body(Clause),      case cerl:is_literal(Body) andalso (cerl:concrete(Body) =:= fail) of	true -> filter_fail_clauses(Left);	false -> [Clause|filter_fail_clauses(Left)]      end;    false ->      [Clause|filter_fail_clauses(Left)]  end;filter_fail_clauses([]) ->  [].bind_guard_case_clauses(GenArgType, GenMap, ArgExpr, [Clause|Left], 			Map, Env, Eval, AccType, AccMaps, State) ->  Pats = cerl:clause_pats(Clause),  {NewMap0, ArgType} =    case Pats of      [Pat] ->	case cerl:is_literal(Pat) of	  true ->	    try	      case cerl:concrete(Pat) of		true -> bind_guard(ArgExpr, Map, Env, pos, State);		false -> bind_guard(ArgExpr, Map, Env, neg, State);		_ -> {GenMap, GenArgType}	      end	    catch 	      throw:{fail, _} -> {none, GenArgType}	    end;	  false ->	    {GenMap, GenArgType}	end;      _ -> {GenMap, GenArgType}    end,  NewMap1 =    case Pats =:= [] of      true -> NewMap0;      false ->	case bind_pat_vars(Pats, t_components(ArgType), [], NewMap0, State) of	  error -> none;	  {PatMap, _PatTypes} -> PatMap	end    end,  Guard = cerl:clause_guard(Clause),  GenPatType = dialyzer_typesig:get_safe_underapprox(Pats, Guard),  NewGenArgType = t_subtract(GenArgType, GenPatType),  case (NewMap1 =:= none) orelse t_is_none(GenArgType) of    true ->      bind_guard_case_clauses(NewGenArgType, GenMap, ArgExpr, Left, Map, Env, 			      Eval, AccType, AccMaps, State);    false ->      {NewAccType, NewAccMaps} =	try	  {NewMap2, GuardType} = bind_guard(Guard, NewMap1, Env, pos, State),	  case t_is_none(t_inf(t_from_term(true), GuardType)) of	    true -> throw({fail, none});	    false -> ok	  end,	  {NewMap3, CType} = bind_guard(cerl:clause_body(Clause), NewMap2, 					Env, Eval, State),	  case Eval of	    pos -> 	      case t_is_atom(true, CType) of		true -> ok;		false -> throw({fail, none})	      end;	    neg -> 	      case t_is_atom(false, CType) of		true -> ok;		false -> throw({fail, none})	      end;	    dont_know ->	      ok	  end,	  {t_sup(AccType, CType), [NewMap3|AccMaps]}	catch	  throw:{fail, _What} -> {AccType, AccMaps}	end,      bind_guard_case_clauses(NewGenArgType, GenMap, ArgExpr, Left, Map, Env, 			      Eval, NewAccType, NewAccMaps, State)  end;bind_guard_case_clauses(_GenArgType, _GenMap, _ArgExpr, [], Map, _Env, _Eval, 			AccType, AccMaps, _State) ->  case t_is_none(AccType) of    true -> throw({fail, none});    false -> {join_maps(AccMaps, Map), AccType}  end.%%% ============================================================================%%%%%%  Maps and types.%%%%%% ============================================================================map__new() ->  {dict:new(), dict:new()}.join_maps(Maps, MapOut) ->  {Map, Subst} = MapOut,  Keys = ordsets:from_list(dict:fetch_keys(Map) ++ dict:fetch_keys(Subst)),  join_maps(Keys, Maps, MapOut).join_maps([Key|Left], Maps, MapOut) ->  Type = join_maps_one_key(Maps, Key, t_none()),  case t_is_equal(lookup_type(Key, MapOut), Type) of    true ->  join_maps(Left, Maps, MapOut);    false -> join_maps(Left, Maps, enter_type(Key, Type, MapOut))  end;join_maps([], _Maps, MapOut) ->  MapOut.join_maps_one_key([Map|Left], Key, AccType) ->  case t_is_any(AccType) of    true ->      %% We can stop here      AccType;    false ->      join_maps_one_key(Left, Key, t_sup(lookup_type(Key, Map), AccType))  end;join_maps_one_key([], _Key, AccType) ->  AccType.enter_type_lists([Key|KeyTail], [Val|ValTail], Map) ->  Map1 = enter_type(Key, Val, Map),  enter_type_lists(KeyTail, ValTail, Map1);enter_type_lists([], [], Map) ->  Map.enter_type_list([{Key, Val}|Left], Map) ->  Map1 = enter_type(Key, Val, Map),  enter_type_list(Left, Map1);enter_type_list([], Map) ->  Map.enter_type(Key, Val, MS = {Map, Subst}) ->    case cerl:is_literal(Key) of    true -> MS;    false ->      case cerl:is_c_values(Key) of	true ->	  Keys = cerl:values_es(Key),	  case t_is_any(Val) orelse t_is_none(Val) of	    true ->	      enter_type_lists(Keys, duplicate(length(Keys), Val), MS);	    false ->	      enter_type_lists(cerl:values_es(Key), t_components(Val), MS)	  end;	false ->	  KeyLabel = get_label(Key),	  case dict:find(KeyLabel, Subst) of	    {ok, NewKey} ->	      ?debug("Binding ~p to ~p\n", [KeyLabel, NewKey]),	      enter_type(NewKey, Val, MS);	    error ->	      ?debug("Entering ~p :: ~s\n", [KeyLabel, t_to_string(Val)]),	      case dict:find(KeyLabel, Map) of		{ok, Val} -> MS;		{ok, _OldVal} -> {dict:store(KeyLabel, Val, Map), Subst};		error -> {dict:store(KeyLabel, Val, Map), Subst}	      end	  end      end  end.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?