dialyzer_dataflow.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 2,097 行 · 第 1/5 页
ERL
2,097 行
case t_is_none(Cons) of true -> error; false -> case bind_pat_vars([cerl:cons_hd(Pat), cerl:cons_tl(Pat)], [t_cons_hd(Cons), t_cons_tl(Cons)], [], Map, State) of error -> error; {Map1, [HdType, TlType]} -> {Map1, t_cons(HdType, TlType)} end end; literal -> Literal = literal_type(Pat), case t_is_none(t_inf(Literal, Type)) of true -> error; false -> {Map, Literal} end; tuple -> Es = cerl:tuple_es(Pat), Prototype = case Es of [] -> t_tuple([]); [Tag|Left] -> case cerl:is_c_atom(Tag) of true -> TagAtom = cerl:atom_val(Tag), case state__lookup_record(TagAtom, length(Left), State) of error -> t_tuple(length(Es)); {ok, Record} -> Record end; false -> t_tuple(length(Es)) end end, Tuple = t_inf(Prototype, Type), case t_is_none(Tuple) of true -> error; false -> SubTuples = t_tuple_subtypes(Tuple), Results = [bind_pat_vars(Es, t_tuple_args(SubTuple), [], Map, State) || SubTuple <- SubTuples], case lists:all(fun(X) -> X =:= error end, Results) of true -> error; false -> Map1 = join_maps([M || {M, _} <- Results], Map), TupleType = t_sup([t_tuple(EsTypes)|| {_, EsTypes} <- Results]), {Map1, TupleType} end end; values -> Es = cerl:values_es(Pat), case bind_pat_vars(Es, t_components(Type), [], Map, State) of error -> error; {Map1, EsTypes} -> {Map1, t_product(EsTypes)} end; var -> %% Must do inf when binding args to pats. Vars in pats are fresh. VarType = t_inf(lookup_type(Pat, Map), Type), case t_is_none(VarType) of true -> error; false -> Map1 = enter_type(Pat, VarType, Map), {Map1, Type} end; _Other -> %% Catch all is needed when binding args to pats ?debug("Failed match for ~p\n", [_Other]), error end, case Res of error -> error; {NewMap, TypeOut} -> bind_pat_vars(PatLeft, TypeLeft, [TypeOut|Acc], NewMap, State) end;bind_pat_vars([], [], Acc, Map, _State) -> {Map, lists:reverse(Acc)};bind_pat_vars(Pats, Type, Acc, Map, State) -> case t_is_any(Type) of true -> bind_pat_vars(Pats, duplicate(length(Pats), t_any()), Acc, Map, State); false -> case t_is_none_or_unit(Type) of true -> error; false -> erlang:fault({'Error binding pats', Pats, Type}) end end. bind_bin_segs([Bitstr|Left], Map) -> %% Only care about Size and Value since the other fields are %% constant literals. Size must be an integer - NO, it can be 'all' Val = cerl:bitstr_val(Bitstr), Size = cerl:bitstr_size(Bitstr), SizeType = case cerl:type(Size) of literal -> %% Safety check case cerl:concrete(Size) of all -> t_from_term(all); N when is_integer(N) -> t_from_term(N) end; var -> t_inf(t_non_neg_integer(), lookup_type(cerl:bitstr_size(Bitstr), Map)) end, ValType = case cerl:type(Val) of literal -> t_from_term(cerl:concrete(Val)); var -> t_any() end, PatType = case cerl:concrete(cerl:bitstr_type(Bitstr)) of float -> t_float(); binary -> t_binary(); integer -> case t_is_integer(SizeType) of true -> case t_number_vals(SizeType) of any -> t_integer(); List -> Unit = cerl:concrete(cerl:bitstr_unit(Bitstr)), SizeVal = lists:max(List), Flags = cerl:concrete(cerl:bitstr_flags(Bitstr)), case lists:member(signed, Flags) of true -> t_from_range(-(1 bsl (SizeVal*Unit - 1)), 1 bsl (SizeVal*Unit - 1) - 1); false -> t_from_range(0, 1 bsl SizeVal*Unit - 1) end end; false -> case t_is_atom(SizeType) of true -> case t_atom_vals(SizeType) of [all] -> t_integer(); _ -> t_none() end; false -> t_none() end end end, Type = t_inf(ValType, PatType), bind_bin_segs(Left, enter_type(Val, Type, enter_type(Size, SizeType, Map)));bind_bin_segs([], Map) -> Map. %%________________________________________%%%% Guards%%bind_guard(Guard, Map, State) -> try bind_guard(Guard, Map, dict:new(), pos, State) of {Map1, _Type} -> Map1 catch throw:{fail, Warning} -> {error, Warning}; throw:{fatal_fail, Warning} -> {error, Warning} end.bind_guard(Guard, Map, Env, Eval, State) -> ?debug("Handling ~w guard: ~s\n", [Eval, cerl_prettypr:format(Guard, [{noann, true}])]), case cerl:type(Guard) of binary -> {Map, t_binary()}; 'case' -> Arg = cerl:case_arg(Guard), Clauses = cerl:case_clauses(Guard), bind_guard_case_clauses(Arg, Clauses, Map, Env, Eval, State); cons -> Hd = cerl:cons_hd(Guard), Tl = cerl:cons_tl(Guard), {Map1, HdType} = bind_guard(Hd, Map, Env, dont_know, State), {Map2, TlType} = bind_guard(Tl, Map1, Env, dont_know, State), {Map2, t_cons(HdType, TlType)}; literal -> {Map, literal_type(Guard)}; 'try' -> Arg = cerl:try_arg(Guard), [Var] = cerl:try_vars(Guard), %%?debug("Storing: ~w\n", [Var]), NewEnv = dict:store(get_label(Var), Arg, Env), bind_guard(cerl:try_body(Guard), Map, NewEnv, Eval, State); tuple -> Es0 = cerl:tuple_es(Guard), {Map1, Es} = bind_guard_list(Es0, Map, Env, dont_know, State), {Map1, t_tuple(Es)}; 'let' -> Arg = cerl:let_arg(Guard), [Var] = cerl:let_vars(Guard), %%?debug("Storing: ~w\n", [Var]), NewEnv = dict:store(get_label(Var), Arg, Env), bind_guard(cerl:let_body(Guard), Map, NewEnv, Eval, State); values -> Es = cerl:values_es(Guard), List = [bind_guard(V, Map, Env, dont_know, State) || V <- Es], Type = t_product([T || {_, T} <- List]), {Map, Type}; var -> ?debug("Looking for var(~w)...", [cerl_trees:get_label(Guard)]), case dict:find(get_label(Guard), Env) of error -> ?debug("Did not find it\n", []), Type = lookup_type(Guard, Map), Constr = case Eval of pos -> t_from_term(true); neg -> t_from_term(false); dont_know -> Type end, Inf = t_inf(Constr, Type), {enter_type(Guard, Inf, Map), Inf}; {ok, Tree} -> ?debug("Found it\n", []), {Map1, Type} = bind_guard(Tree, Map, Env, Eval, State), {enter_type(Guard, Type, Map1), Type} end; call -> Args = cerl:call_args(Guard), MFA = {cerl:atom_val(cerl:call_module(Guard)), cerl:atom_val(cerl:call_name(Guard)), length(Args)}, case MFA of {erlang, F, 1} when F =:= is_atom; F =:= is_boolean; F =:= is_binary; F =:= is_float; F =:= is_function; F =:= is_integer; F =:= is_list; F =:= is_number; F =:= is_pid; F =:= is_port; F =:= is_reference; F =:= is_tuple -> [Arg] = Args, {Map1, ArgType} = bind_guard(Arg, Map, Env, dont_know, State), case bind_type_test(Eval, F, ArgType) of error -> ?debug("Type test: ~w failed\n", [F]), signal_guard_fail(Guard, [ArgType], State); {ok, NewArgType, Ret} -> ?debug("Type test: ~w succeeded, NewType: ~s, Ret: ~s\n", [F, t_to_string(NewArgType), t_to_string(Ret)]), {enter_type(Arg, NewArgType, Map1), Ret} end; {erlang, is_function, 2} -> {Map1, [FunType0, ArityType0]} = bind_guard_list(Args, Map, Env, dont_know, State), ArityType = t_inf(ArityType0, t_integer()), case t_is_none(ArityType) of true -> signal_guard_fail(Guard, [FunType0, ArityType0], State); false -> FunTypeConstr = case t_number_vals(ArityType) of any -> t_fun(); Vals -> t_sup([t_fun(duplicate(X, t_any()), t_any())|| X <- Vals]) end, FunType = t_inf(FunType0, FunTypeConstr), case t_is_none(FunType) of true -> case Eval of pos -> signal_guard_fail(Guard, [FunType0, ArityType0], State); neg -> {Map1, t_atom(false)}; dont_know -> {Map1, t_atom(false)} end; false -> case Eval of pos -> {enter_type_lists(Args, [FunType, ArityType], Map1), t_atom(true)}; neg -> {Map1, t_atom(false)}; dont_know -> {Map1, t_bool()} end end end; MFA when (MFA =:= {erlang, internal_is_record, 3}) or (MFA =:= {erlang, is_record, 3}) -> [Rec, Tag0, Arity0] = Args, Tag = cerl:atom_val(Tag0), Arity = cerl:int_val(Arity0), {Map1, RecType} = bind_guard(Rec, Map, Env, dont_know, State), TupleType = case state__lookup_record(Tag, Arity - 1, State) of error -> t_tuple([t_atom(Tag)|duplicate(Arity - 1, t_any())]); {ok, Prototype} -> Prototype end, Type = t_inf(TupleType, RecType), case t_is_none(Type) of true -> case Eval of pos -> signal_guard_fail(Guard, [RecType, t_from_term(Tag), t_from_term(Arity)], State); neg -> {Map1, t_atom(false)}; dont_know -> {Map1, t_atom(false)} end; false -> case Eval of pos -> {enter_type(Rec, Type, Map1), t_atom(true)}; neg -> {Map1, t_atom(false)}; dont_know -> {Map1, t_bool()} end end; {erlang, '=:=', 2} -> [Arg1, Arg2] = Args, case {cerl:type(Arg1), cerl:type(Arg2)} of {literal, literal} -> case cerl:concrete(Arg1) =:= cerl:concrete(Arg2) of true -> if Eval =:= neg -> throw({fail, none}); Eval =:= pos -> {Map, t_from_term(true)}; Eval =:= dont_know -> {Map, t_from_term(true)} end; false -> if Eval =:= neg -> {Map, t_from_term(false)}; Eval =:= dont_know -> {Map, t_from_term(false)}; Eval =:= pos -> ArgTypes = [t_from_term(cerl:concrete(Arg1)), t_from_term(cerl:concrete(Arg2))], signal_guard_fail(Guard, ArgTypes, State) end end; {literal, _} when Eval =:= pos -> bind_eqeq_guard_lit_other(Guard, Arg1, Arg2, Map, Env, State); {_, literal} when Eval =:= pos -> bind_eqeq_guard_lit_other(Guard, Arg2, Arg1, Map, Env, State); {_, _} -> bind_eqeq_guard(Guard, Arg1, Arg2, Map, Env, Eval, State) end; {erlang, '==', 2} -> [Arg1, Arg2] = Args, case {cerl:type(Arg1), cerl:type(Arg2)} of {literal, literal} -> case cerl:concrete(Arg1) == cerl:concrete(Arg2) of true -> if Eval =:= pos -> {Map, t_from_term(true)}; Eval =:= neg -> throw({fail, none}); Eval =:= dont_know -> {Map, t_from_term(true)} end; false -> if Eval =:= neg -> {Map, t_from_term(false)}; Eval =:= dont_know -> {Map, t_from_term(false)}; Eval =:= pos -> ArgTypes = [t_from_term(cerl:concrete(Arg1)), t_from_term(cerl:concrete(Arg2))], signal_guard_fail(Guard, ArgTypes, State) end end; {literal, _} when Eval =:= pos -> case cerl:concrete(Arg1) of Atom when is_atom(Atom) -> bind_eqeq_guard_lit_other(Guard, Arg1, Arg2, Map, Env, State); [] -> bind_eqeq_guard_lit_other(Guard, Arg1, Arg2, Map, Env, State); _ -> bind_eq_guard(Guard, Arg1, Arg2, Map, Env, Eval, State) end; {_, literal} when Eval =:= pos -> case cerl:concrete(Arg2) of Atom when is_atom(Atom) -> bind_eqeq_guard_lit_other(Guard, Arg2, Arg1, Map, Env, State); [] -> bind_eqeq_guard_lit_other(Guard, Arg2, Arg1, Map, Env, State); _ -> bind_eq_guard(Guard, Arg1, Arg2, Map, Env, Eval, State) end; {_, _} -> bind_eq_guard(Guard, Arg1, Arg2, Map, Env, Eval, State) end; {erlang, 'and', 2} -> [Arg1, Arg2] = Args, case Eval of pos -> {Map1, Type1} = bind_guard(Arg1, Map, Env, Eval, State), case t_is_atom(true, Type1) of false -> throw({fail, none}); true -> {Map2, Type2} = bind_guard(Arg2, Map1, Env, Eval, State), case t_is_atom(true, Type2) of false -> throw({fail, none}); true -> {Map2, t_atom(true)} end end; neg -> {Map1, Type1} = try bind_guard(Arg1, Map, Env, neg, State) catch throw:{fail, _} -> bind_guard(Arg2, Map, Env, pos, State) end, {Map2, Type2} = try bind_guard(Arg1, Map, Env, neg, State) catch throw:{fail, _} -> bind_guard(Arg2, Map, Env, pos, State) end, case t_is_atom(false, Type1) orelse t_is_atom(false, Type2) of true -> {join_maps([Map1, Map2], Map), t_from_term(false)}; false -> throw({fail, none}) end; dont_know -> True = t_atom(true), {Map1, Type1} = bind_guard(Arg1, Map, Env, dont_know, State), case t_is_none(t_inf(Type1, t_bool())) of true -> throw({fail, none}); false -> {Map2, Type2} = bind_guard(Arg2, Map1, Env, Eval, State), case t_is_none(t_inf(Type2, t_bool())) of true -> throw({fail, none}); false -> {Map2, True} end end end; {erlang, 'or', 2} -> [Arg1, Arg2] = Args, case Eval of pos -> {Map1, Bool1} = try bind_guard(Arg1, Map, Env, pos, State) catch throw:{fail,_} -> bind_guard(Arg1, Map, Env, dont_know, State) end, {Map2, Bool2} = try bind_guard(Arg2, Map, Env, pos, State) catch throw:{fail,_} -> bind_guard(Arg2, Map, Env, dont_know, State)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?