diff options
Diffstat (limited to 'lib/dialyzer/src/dialyzer_dataflow.erl')
-rw-r--r-- | lib/dialyzer/src/dialyzer_dataflow.erl | 66 |
1 files changed, 47 insertions, 19 deletions
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index 33fa107019..692684cd99 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -58,10 +58,12 @@ t_fun_range/2, t_integer/0, t_integers/1, t_is_any/1, t_is_atom/1, t_is_atom/2, t_is_any_atom/3, t_is_boolean/2, - t_is_integer/2, t_is_nil/2, t_is_none/1, t_is_none_or_unit/1, + t_is_integer/2, t_is_list/1, + t_is_nil/2, t_is_none/1, t_is_none_or_unit/1, t_is_number/2, t_is_reference/2, t_is_pid/2, t_is_port/2, t_is_unit/1, - t_limit/2, t_list/0, t_maybe_improper_list/0, t_module/0, + t_limit/2, t_list/0, t_list_elements/2, + t_maybe_improper_list/0, t_module/0, t_none/0, t_non_neg_integer/0, t_number/0, t_number_vals/2, t_pid/0, t_port/0, t_product/1, t_reference/0, t_to_string/2, t_to_tlist/1, @@ -84,39 +86,53 @@ %%-------------------------------------------------------------------- +-type type() :: erl_types:erl_type(). +-type types() :: erl_types:type_table(). + -define(no_arg, no_arg). -define(TYPE_LIMIT, 3). -record(state, {callgraph :: dialyzer_callgraph:callgraph(), - envs :: dict(), - fun_tab :: dict(), + envs :: env_tab(), + fun_tab :: fun_tab(), plt :: dialyzer_plt:plt(), - opaques :: [erl_types:erl_type()], + opaques :: [type()], races = dialyzer_races:new() :: dialyzer_races:races(), - records = dict:new() :: dict(), - tree_map :: dict(), + records = dict:new() :: types(), + tree_map :: dict:dict(label(), cerl:cerl()), warning_mode = false :: boolean(), warnings = [] :: [dial_warning()], - work :: {[_], [_], set()}, + work :: {[_], [_], sets:set()}, module :: module() }). --record(map, {dict = dict:new() :: dict(), - subst = dict:new() :: dict(), +-record(map, {dict = dict:new() :: type_tab(), + subst = dict:new() :: subst_tab(), modified = [] :: [Key :: term()], modified_stack = [] :: [{[Key :: term()],reference()}], ref = undefined :: reference() | undefined}). +-type nowarn() :: dialyzer_analysis_callgraph:no_warn_unused(). +-type env_tab() :: dict:dict(label(), #map{}). +-type fun_entry() :: {Args :: [type()], RetType :: type()}. +-type fun_tab() :: dict:dict('top' | label(), + {'not_handled', fun_entry()} | fun_entry()). +-type key() :: label() | cerl:cerl(). +-type type_tab() :: dict:dict(key(), type()). +-type subst_tab() :: dict:dict(key(), cerl:cerl()). + %% Exported Types -opaque state() :: #state{}. %%-------------------------------------------------------------------- +-type fun_types() :: dict:dict(label(), type()). + -spec get_warnings(cerl:c_module(), dialyzer_plt:plt(), - dialyzer_callgraph:callgraph(), dict(), set()) -> - {[dial_warning()], dict()}. + dialyzer_callgraph:callgraph(), types(), nowarn()) -> + {[dial_warning()], fun_types()}. get_warnings(Tree, Plt, Callgraph, Records, NoWarnUnused) -> State1 = analyze_module(Tree, Plt, Callgraph, Records, true), @@ -127,7 +143,8 @@ get_warnings(Tree, Plt, Callgraph, Records, NoWarnUnused) -> {State4#state.warnings, state__all_fun_types(State4)}. -spec get_fun_types(cerl:c_module(), dialyzer_plt:plt(), - dialyzer_callgraph:callgraph(), dict()) -> dict(). + dialyzer_callgraph:callgraph(), + types()) -> fun_types(). get_fun_types(Tree, Plt, Callgraph, Records) -> State = analyze_module(Tree, Plt, Callgraph, Records, false), @@ -293,6 +310,7 @@ traverse(Tree, Map, State) -> t_is_any(ArgType) orelse t_is_simple(ArgType, State) orelse is_call_to_send(Arg) + orelse is_lc_simple_list(Arg, ArgType, State) of true -> % do not warn in these cases State1; @@ -2296,12 +2314,15 @@ bind_guard_list([], Map, _Env, _Eval, _State, Acc) -> -type eval() :: 'pos' | 'neg' | 'dont_know'. --spec signal_guard_fail(eval(), cerl:c_call(), [erl_types:erl_type()], +-spec signal_guard_fail(eval(), cerl:c_call(), [type()], state()) -> no_return(). signal_guard_fail(Eval, Guard, ArgTypes, State) -> signal_guard_failure(Eval, Guard, ArgTypes, fail, State). +-spec signal_guard_fatal_fail(eval(), cerl:c_call(), [erl_types:erl_type()], + state()) -> no_return(). + signal_guard_fatal_fail(Eval, Guard, ArgTypes, State) -> signal_guard_failure(Eval, Guard, ArgTypes, fatal_fail, State). @@ -2710,6 +2731,13 @@ is_call_to_send(Tree) -> andalso (Arity =:= 2) end. +is_lc_simple_list(Tree, TreeType, State) -> + Opaques = State#state.opaques, + Ann = cerl:get_ann(Tree), + lists:member(list_comprehension, Ann) + andalso t_is_list(TreeType) + andalso t_is_simple(t_list_elements(TreeType, Opaques), State). + filter_match_fail([Clause] = Cls) -> Body = cerl:clause_body(Clause), case cerl:type(Body) of @@ -3148,7 +3176,7 @@ state__get_callgraph(#state{callgraph = Callgraph}) -> state__get_races(#state{races = Races}) -> Races. --spec state__get_records(state()) -> dict(). +-spec state__get_records(state()) -> types(). state__get_records(#state{records = Records}) -> Records. @@ -3247,7 +3275,7 @@ get_file([_|Tail]) -> get_file(Tail). is_compiler_generated(Ann) -> lists:member(compiler_generated, Ann) orelse (get_line(Ann) < 1). --spec format_args([cerl:cerl()], [erl_types:erl_type()], state()) -> +-spec format_args([cerl:cerl()], [type()], state()) -> nonempty_string(). format_args([], [], _State) -> @@ -3282,17 +3310,17 @@ format_arg(Arg) -> Default end. --spec format_type(erl_types:erl_type(), state()) -> string(). +-spec format_type(type(), state()) -> string(). format_type(Type, #state{records = R}) -> t_to_string(Type, R). --spec format_field_diffs(erl_types:erl_type(), state()) -> string(). +-spec format_field_diffs(type(), state()) -> string(). format_field_diffs(RecConstruction, #state{records = R}) -> erl_types:record_field_diffs_to_string(RecConstruction, R). --spec format_sig_args(erl_types:erl_type(), state()) -> string(). +-spec format_sig_args(type(), state()) -> string(). format_sig_args(Type, #state{opaques = Opaques} = State) -> SigArgs = t_fun_args(Type, Opaques), |