aboutsummaryrefslogtreecommitdiffstats
path: root/lib/dialyzer/src/dialyzer_dataflow.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dialyzer/src/dialyzer_dataflow.erl')
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl66
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),