dialyzer_icode.erl

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

ERL
2,150
字号
%% -*- erlang-indent-level: 2 -*-%%--------------------------------------------------------------------%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% Copyright 2006, Tobias Lindahl and Kostis Sagonas%% %%     $Id$%%%%%-------------------------------------------------------------------%%% File    : dialyzer_icode.erl%%% Author  : Tobias Lindahl <tobiasl@it.uu.se>%%% Description : %%%%%% Created : 15 Apr 2005 by Tobias Lindahl <tobiasl@it.uu.se>%%%--------------------------------------------------------------------module(dialyzer_icode).-export([run_analysis/5]).-include("hipe_icode.hrl").-include("dialyzer.hrl").-define(TYPE_DEPTH, 3).-import(erl_types, [t_any/0, t_atom/1, t_atom/0, t_atom_vals/1,		    t_binary/0, t_bool/0, t_cons/0, t_constant/0, 		    t_pos_improper_list/0,		    t_float/0, t_from_term/1, t_fun/0, t_fun/1, t_fun/2,		    t_fun_args/1, t_fun_arity/1,		    t_fun_range/1,t_inf/2, t_inf_lists/2, 		    t_integer/0,		    t_integer/1, t_is_atom/1, t_is_atom/2, 		    t_is_any/1, t_is_binary/1,		    t_is_bool/1, t_is_cons/1, t_is_constant/1,		    t_is_pos_improper_list/1, t_is_equal/2, t_is_float/1,		    t_is_fun/1, t_is_integer/1, t_is_number/1,		    t_is_list/1, t_is_nil/1, t_is_port/1, t_is_pid/1,		    t_is_ref/1, t_is_subtype/2, 		    t_is_tuple/1,		    t_is_none/1, t_limit/2, t_list/0, t_nil/0,		    t_number/0, t_number/1, t_number_vals/1, t_pid/0,		    t_port/0, t_product/1, t_ref/0, t_subtract/2, 		    t_sup/1, t_sup/2,		    t_to_string/1, t_tuple/0, t_tuple/1,		    t_tuple_arities/1, t_none/0]).-record(state, {succmap, predmap, info_map, cfg, liveness, arg_types,		created_funs=[]}).%%-define(DEBUG, true).run_analysis(Cfg, IcodeFun, Plt, NoWarnUnused, SendWarn) ->  OldSig = init_mfa_info(IcodeFun, Plt),  State = analyze(Cfg),  pp(State, IcodeFun, "Pre-specialization"),  NewState = cfg_loop(State),  pp(NewState, IcodeFun, "Post-specialization"),  Warnings =    case SendWarn of      true -> warn_on_type_errors(Cfg, State, NewState, NoWarnUnused, IcodeFun);      false -> []    end,  return(NewState, IcodeFun, OldSig, Warnings).cfg_loop(State) ->  Labels = hipe_icode_cfg:reverse_postorder(state__cfg(State)),    simplify_controlflow(Labels, State).return(State, IcodeFun, OldSig, Warnings) ->  Labels = hipe_icode_cfg:labels(state__cfg(State)),  {IcodeReturn0, _, _} = find_return_type(Labels, State),  IcodeArgs = State#state.arg_types,  case t_is_none(IcodeReturn0) of    true ->      IcodeReturn = t_any();    false ->      IcodeReturn = IcodeReturn0  end,    NewArgs =      case t_fun_args(OldSig) of      any -> IcodeArgs;      PltArgs -> PltArgs    end,    Fixpoint =       case t_is_equal(IcodeReturn, t_fun_range(OldSig)) of      true -> fixpoint;      false -> not_fixpoint    end,  {Fixpoint, {IcodeFun, IcodeReturn, NewArgs}, Warnings}.%% _________________________________________________________________%% %% Global type analysis on the whole function. Demands that the code%% is in SSA-form. When we encounter a phi-node, the types of the%% arguments are joined. At the end of a block the information out is%% joined with the current information in for all _valid_ successors,%% that is, of all successors that actually can be reached. If the%% join produces new information in for the successor, this%% information is added to the worklist.%%analyze(Cfg) ->  %%hipe_icode_cfg:pp(Cfg),  State1 = new_state(Cfg),  analyze_blocks(State1).analyze_blocks(State) ->  Work = init_work(State),  analyze_blocks(Work, State).analyze_blocks(Work, State) ->  case get_work(Work) of    fixpoint ->      State;    {Label, NewWork} ->      Info = state__info_in(State, Label),      {NewState2, NewLabels} = analyze_block(Label, Info, State),      NewWork2 = add_work(NewWork, NewLabels),      analyze_blocks(NewWork2, NewState2)  end.  analyze_block(Label, InfoIn, State) ->  %%io:format("Handling ~w\n", [Label]),  BB = state__bb(State, Label),  Code = hipe_bb:butlast(BB),  Last = hipe_bb:last(BB),  InfoOut = analyze_insns(Code, InfoIn),  NewState = state__info_out_update(State, Label, InfoOut),  case Last of    #'if'{} ->      UpdateInfo = do_if(Last, InfoOut),      do_updates(NewState, UpdateInfo);    #type{} ->      UpdateInfo = do_type(Last, InfoOut),      do_updates(NewState, UpdateInfo);    #switch_tuple_arity{} ->      UpdateInfo = do_switch_tuple_arity(Last, InfoOut),      do_updates(NewState, UpdateInfo);    #switch_val{} ->      UpdateInfo = do_switch_val(Last, InfoOut),      do_updates(NewState, UpdateInfo);    #call{} ->      {DstType, NewArgTypes} = do_call(Last, InfoOut),      NewInfoOut = enter_defines(Last, DstType, InfoOut),      NewState1 = state__info_out_update(NewState, Label, NewInfoOut),      ContInfo = enter_lists(args(Last), NewArgTypes, NewInfoOut),      Cont = hipe_icode:call_continuation(Last),      Fail = hipe_icode:call_fail_label(Last),      UpdateInfo =	case Fail of	  [] ->	    case call_always_fails(Last, InfoOut) of	       true ->		[];	      false ->		[{Cont, ContInfo}]	    end;	  _ ->	    case call_always_fails(Last, InfoOut) of	      true ->		[{Fail, NewInfoOut}];	      false ->		Fun = hipe_icode:call_fun(Last),		case hipe_icode_primops:fails(Fun) of		  true ->		    [{Cont, ContInfo}, {Fail, NewInfoOut}];		  false ->		    [{Cont, ContInfo}]		end	    end	end,      do_updates(NewState1, UpdateInfo);    _ ->      UpdateInfo = [{X, InfoOut}||X<-state__succ(NewState, Label)],      do_updates(NewState, UpdateInfo)  end.analyze_insns([I|Insns], Info) ->  NewInfo = analyze_insn(I, Info),  analyze_insns(Insns, NewInfo);analyze_insns([], Info) ->  Info.analyze_insn(I, Info) ->  case I of    #move{} ->      do_move(I, Info);    #call{} ->      {DstType, NewArgTypes} = do_call(I, Info),      NewInfo = enter_defines(I, DstType, Info),      enter_lists(args(I), NewArgTypes, NewInfo);    #phi{} ->      Type = t_limit(join_list(args(I), Info), ?TYPE_DEPTH),      enter_defines(I, Type, Info);    #begin_handler{} ->      enter_defines(I, t_any(), Info);    _ ->      %% Just an assert      case defines(I) of	[] -> Info;	_ -> erlang:fault({"Instruction with destination not analyzed", I})      end  end.do_move(I, Info) ->  %% Can't use uses/1 since we must keep constants.  [Src] = args(I),  case hipe_icode:is_const(Src) of    true ->       enter_defines(I, const_type(Src), Info);    false ->      %% Make the destination point to the source.      enter_defines(I, Src, Info)  end.do_call(I, Info) ->  Fun = hipe_icode:call_fun(I),  CallType = hipe_icode:call_type(I),  call_or_enter_type(I, Fun, args(I), Info, CallType).call_or_enter_type(_I, Fun, Args, Info, primop) ->  ArgTypes = lookup_list(Args, Info),  DstType = primop_type(Fun, ArgTypes),        case t_fun_args(find_signature_primop(Fun, length(ArgTypes))) of    any -> {DstType, ArgTypes};    ArgConstr -> {DstType, t_inf_lists(ArgTypes, ArgConstr)}  end;call_or_enter_type(I, MFA, Args, Info, OtherType) when OtherType =:= local;						       OtherType =:= remote ->  ArgTypes = lookup_list(Args, Info),  PltSig = find_signature(MFA, ArgTypes),  {M, F, A} = MFA,  BifType = erl_bif_types:type(M, F, A, ArgTypes),  %% XXX: This should be removed when the annotated form is not used anymore.  AnnotatedType =    case I of      #call{} ->	case hipe_icode:call_dst_type(I) of	  [] -> t_any();	  T -> 	    %% Make sure that the core type pass has not 	    %% annotated this with none()	    case t_is_none(T) of	      true -> t_any();	      false -> T	    end	end;      #enter{} ->	t_any()    end,  DstType = t_inf(AnnotatedType, t_inf(BifType, t_fun_range(PltSig))),  case t_fun_args(PltSig) of    any ->      {DstType, ArgTypes};    ArgConstr ->            NewArgTypes = t_inf_lists(ArgTypes, ArgConstr),      case any_is_none(NewArgTypes) of	true -> {t_none(), NewArgTypes};	false -> {DstType, NewArgTypes}      end  end.do_if(I, Info) ->  %%% XXX: Could probably do better than this.  TrueLab = hipe_icode:if_true_label(I),  FalseLab = hipe_icode:if_false_label(I),  case hipe_icode:if_args(I) of    [Arg1, Arg2] = Args ->      [Type1, Type2] = lookup_list(Args, Info),      %% io:format("Type1 = ~w, Type2 = ~w\n", [Type1, Type2]),      case t_is_none(Type1) orelse t_is_none(Type2) of	true ->	  [{TrueLab, Info}, {FalseLab, Info}];	false ->	  Inf = t_inf(Type1, Type2),	  case hipe_icode:if_op(I) of	    '=:='->	      case t_is_none(Inf) of		true -> [{FalseLab, Info}];		false -> [{TrueLab, enter(Arg1, Inf, enter(Arg2, Inf, Info))}, 			  {FalseLab, Info}]	      end;	    '=/=' ->	      case t_is_none(Inf) of		true -> 		  [{TrueLab, Info}];		false ->		  [{FalseLab, enter(Arg1, Inf, enter(Arg2, Inf, Info))}, 		   {TrueLab, Info}]	      end;	    Op ->	      Eval = erl_bif_types:type(erlang, Op, 2, [Type1, Type2]),	      case t_is_atom(true, Eval) of		true -> [{TrueLab, Info}];		false ->		  case t_is_atom(false, Eval) of		    true -> [{FalseLab, Info}];		    false -> [{TrueLab, Info}, {FalseLab, Info}]		  end	      end	  end      end;    _ ->      %% Only care for binary if:s      [{TrueLab, Info}, {FalseLab, Info}]  end.do_type(I, Info) ->  case args(I) of    [Var] -> do_type(I, Info, Var);    [Var1,Var2] -> do_type2(I, Info, Var1, Var2)  end.do_type2(I, Info, FunVar, ArityVar) -> % function2(Fun,Arity)  %% Just for sanity.  function2 = hipe_icode:type_type(I),    FunType = lookup(FunVar, Info),  ArityType = lookup(ArityVar, Info),  TrueLab = hipe_icode:type_true_label(I),  FalseLab = hipe_icode:type_false_label(I),  case combine_test(test_type(function, FunType), 		    test_type(integer, ArityType)) of    true ->      Arity = t_fun_arity(FunType),      case t_number_vals(ArityType) of	any ->	  if Arity =/= any -> [{TrueLab, Info}, {FalseLab, Info}];	     true -> [{TrueLab, enter(ArityVar, t_from_term(Arity), Info)},		      {FalseLab, Info}]	  end;	[Arity] ->	  [{TrueLab, Info}];	List ->	  case lists:member(Arity, List) of	    true ->	      T = t_from_term(Arity), 	      [{TrueLab, enter(ArityVar, T, Info)},	       {FalseLab, enter(ArityVar, t_subtract(ArityType, T), Info)}];	    false ->	      [{FalseLab, Info}]	  end      end;    false ->      [{FalseLab, Info}];    maybe ->      GenTrueArity = t_inf(t_integer(), ArityType),      GenTrueFun = t_inf(t_fun(), FunType),      case {t_number_vals(GenTrueArity), t_fun_arity(GenTrueFun)} of	{any, any} -> 	  TrueInfo = enter_lists([FunVar, ArityVar], 				 [GenTrueFun, GenTrueArity], Info),	  [{TrueLab, TrueInfo}, {FalseLab, Info}];	{any, Arity} when is_integer(Arity) ->	  TrueInfo = enter_lists([FunVar, ArityVar], 				 [GenTrueFun, t_integer(Arity)], Info),	  [{TrueLab, TrueInfo}, {FalseLab, Info}];	{[Val], any} when is_integer(Val) ->	  TrueInfo = enter_lists([FunVar, ArityVar], 				 [t_inf(GenTrueFun, t_fun(Val, t_any())),				  GenTrueArity], Info),	  [{TrueLab, TrueInfo}, {FalseLab, Info}];	{Vals, any} when is_list(Vals) ->	  %% The function type gets widened when we have more than one arity.	  TrueInfo = enter_lists([FunVar, ArityVar], 				 [GenTrueFun, GenTrueArity], Info),	  [{TrueLab, TrueInfo}, {FalseLab, Info}];	{Vals, Arity} when is_list(Vals), is_integer(Arity) ->	  case lists:member(Arity, Vals) of	    false ->	      [{FalseLab, Info}];	    true ->	      TrueInfo = enter_lists([FunVar, ArityVar], 				     [GenTrueFun, t_integer(Arity)], Info),	      [{TrueLab, TrueInfo}, {FalseLab, Info}]	  end      end  end.combine_test(true, true) -> true;combine_test(false, _)   -> false;combine_test(_, false)   -> false;combine_test(_, _)       -> maybe.do_type(I, Info, Var) ->  TrueLab = hipe_icode:type_true_label(I),  FalseLab = hipe_icode:type_false_label(I),  None = t_none(),    case lookup(Var, Info) of    None ->      [{TrueLab, Info}, {FalseLab, Info}];    VarInfo ->      case hipe_icode:type_type(I) of	cons ->	  test_cons_or_nil(t_cons(), Var, VarInfo, TrueLab, FalseLab, Info);	nil ->	  test_cons_or_nil(t_nil(), Var, VarInfo, TrueLab, FalseLab, Info);	{atom, A} ->	  test_number_or_atom(fun(X) -> t_atom(X) end,			      A, Var, VarInfo, {atom, A}, 			      TrueLab, FalseLab, Info);	{integer, N} ->	  test_number_or_atom(fun(X) -> t_number(X) end, 			      N, Var, VarInfo, {integer, N}, 			      TrueLab, FalseLab, Info);	{record, Atom, Size} ->	  test_record(Atom, Size, Var, VarInfo, TrueLab, FalseLab, Info);	Other ->	  case t_is_any(VarInfo) of	    true ->	      TrueType = t_inf(true_branch_info(Other), VarInfo),	      TrueInfo = enter(Var, TrueType, Info),	      [{TrueLab, TrueInfo}, {FalseLab, Info}];	    false ->

⌨️ 快捷键说明

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