diff options
Diffstat (limited to 'lib/dialyzer')
7 files changed, 58 insertions, 34 deletions
diff --git a/lib/dialyzer/src/dialyzer_behaviours.erl b/lib/dialyzer/src/dialyzer_behaviours.erl index 56eb46d78a..900ddf28c5 100644 --- a/lib/dialyzer/src/dialyzer_behaviours.erl +++ b/lib/dialyzer/src/dialyzer_behaviours.erl @@ -144,15 +144,20 @@ check_all_callbacks(Module, Behaviour, [Cb|Rest], 'error' -> Acc1; {ok, {{File, Line}, Contract}} -> Acc10 = Acc1, - SpecReturnType = dialyzer_contracts:get_contract_return(Contract), - SpecArgTypes = dialyzer_contracts:get_contract_args(Contract), + SpecReturnType0 = dialyzer_contracts:get_contract_return(Contract), + SpecArgTypes0 = dialyzer_contracts:get_contract_args(Contract), + SpecReturnType = erl_types:subst_all_vars_to_any(SpecReturnType0), + SpecArgTypes = + [erl_types:subst_all_vars_to_any(ArgT0) || ArgT0 <- SpecArgTypes0], Acc11 = case erl_types:t_is_subtype(SpecReturnType, CbReturnType) of true -> Acc10; - false -> [{callback_spec_type_mismatch, - [File, Line, Behaviour, Function, Arity, - erl_types:t_to_string(SpecReturnType, Records), - erl_types:t_to_string(CbReturnType, Records)]}|Acc10] + false -> + ExtraType = erl_types:t_subtract(SpecReturnType, CbReturnType), + [{callback_spec_type_mismatch, + [File, Line, Behaviour, Function, Arity, + erl_types:t_to_string(ExtraType, Records), + erl_types:t_to_string(CbReturnType, Records)]}|Acc10] end, Acc12 = case erl_types:any_none( diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl index 732bd4ac84..04a0db890f 100644 --- a/lib/dialyzer/src/dialyzer_cl.erl +++ b/lib/dialyzer/src/dialyzer_cl.erl @@ -29,10 +29,6 @@ -module(dialyzer_cl). -%% Avoid warning for local function error/1 clashing with autoimported BIF. --compile({no_auto_import,[error/1]}). -%% Avoid warning for local function error/2 clashing with autoimported BIF. --compile({no_auto_import,[error/2]}). -export([start/1]). -include("dialyzer.hrl"). @@ -88,7 +84,7 @@ init_opts_for_build(Opts) -> Plts -> Msg = io_lib:format("Could not build multiple PLT files: ~s\n", [format_plts(Plts)]), - error(Msg) + cl_error(Msg) end; false -> Opts#options{init_plts = []} end. @@ -110,7 +106,7 @@ init_opts_for_add(Opts) -> Plts -> Msg = io_lib:format("Could not add to multiple PLT files: ~s\n", [format_plts(Plts)]), - error(Msg) + cl_error(Msg) end; false -> case Opts#options.init_plts =:= [] of @@ -134,11 +130,12 @@ check_plt_aux([_] = Plt, Opts) -> report_check(Opts2), plt_common(Opts2, [], []); check_plt_aux([Plt|Plts], Opts) -> - Opts1 = Opts#options{init_plts = [Plt]}, - Opts2 = init_opts_for_check(Opts1), - report_check(Opts2), - plt_common(Opts2, [], []), - check_plt_aux(Plts, Opts). + case check_plt_aux([Plt], Opts) of + {?RET_NOTHING_SUSPICIOUS, []} -> check_plt_aux(Plts, Opts); + {?RET_DISCREPANCIES, Warns} -> + {_RET, MoreWarns} = check_plt_aux(Plts, Opts), + {?RET_DISCREPANCIES, Warns ++ MoreWarns} + end. init_opts_for_check(Opts) -> InitPlt = @@ -175,7 +172,7 @@ init_opts_for_remove(Opts) -> Plts -> Msg = io_lib:format("Could not remove from multiple PLT files: ~s\n", [format_plts(Plts)]), - error(Msg) + cl_error(Msg) end; false -> case Opts#options.init_plts =:= [] of @@ -193,7 +190,7 @@ plt_common(#options{init_plts = [InitPlt]} = Opts, RemoveFiles, AddFiles) -> none -> ok; OutPlt -> {ok, Binary} = file:read_file(InitPlt), - file:write_file(OutPlt, Binary) + ok = file:write_file(OutPlt, Binary) end, case Opts#options.report_mode of quiet -> ok; @@ -221,19 +218,19 @@ plt_common(#options{init_plts = [InitPlt]} = Opts, RemoveFiles, AddFiles) -> {error, no_such_file} -> Msg = io_lib:format("Could not find the PLT: ~s\n~s", [InitPlt, default_plt_error_msg()]), - error(Msg); + cl_error(Msg); {error, not_valid} -> Msg = io_lib:format("The file: ~s is not a valid PLT file\n~s", [InitPlt, default_plt_error_msg()]), - error(Msg); + cl_error(Msg); {error, read_error} -> Msg = io_lib:format("Could not read the PLT: ~s\n~s", [InitPlt, default_plt_error_msg()]), - error(Msg); + cl_error(Msg); {error, {no_file_to_remove, F}} -> Msg = io_lib:format("Could not remove the file ~s from the PLT: ~s\n", [F, InitPlt]), - error(Msg) + cl_error(Msg) end. default_plt_error_msg() -> @@ -426,7 +423,7 @@ assert_writable(PltFile) -> true -> ok; false -> Msg = io_lib:format(" The PLT file ~s is not writable", [PltFile]), - error(Msg) + cl_error(Msg) end. check_if_writable(PltFile) -> @@ -550,7 +547,7 @@ init_output(State0, #options{output_file = OutFile, {error, Reason} -> Msg = io_lib:format("Could not open output file ~p, Reason: ~p\n", [OutFile, Reason]), - error(State, lists:flatten(Msg)) + cl_error(State, lists:flatten(Msg)) end end. @@ -596,10 +593,10 @@ cl_loop(State, LogCache) -> cl_loop(NewState, LogCache); {'EXIT', BackendPid, {error, Reason}} -> Msg = failed_anal_msg(Reason, LogCache), - error(State, Msg); + cl_error(State, Msg); {'EXIT', BackendPid, Reason} when Reason =/= 'normal' -> Msg = failed_anal_msg(io_lib:format("~P", [Reason, 12]), LogCache), - error(State, Msg); + cl_error(State, Msg); _Other -> %% io:format("Received ~p\n", [_Other]), cl_loop(State, LogCache) @@ -632,14 +629,14 @@ store_warnings(#cl_state{stored_warnings = StoredWarnings} = St, Warnings) -> store_unknown_behaviours(#cl_state{unknown_behaviours = Behs} = St, Beh) -> St#cl_state{unknown_behaviours = Beh ++ Behs}. --spec error(string()) -> no_return(). +-spec cl_error(string()) -> no_return(). -error(Msg) -> +cl_error(Msg) -> throw({dialyzer_error, Msg}). --spec error(#cl_state{}, string()) -> no_return(). +-spec cl_error(#cl_state{}, string()) -> no_return(). -error(State, Msg) -> +cl_error(State, Msg) -> case State#cl_state.output of standard_io -> ok; Outfile -> io:format(Outfile, "\n~s\n", [Msg]) diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl index 92868b6878..4268814859 100644 --- a/lib/dialyzer/src/dialyzer_typesig.erl +++ b/lib/dialyzer/src/dialyzer_typesig.erl @@ -2046,8 +2046,7 @@ lookup_type(Key, Map) -> %% case cerl:is_literal(Key) of %% true -> t_from_term(cerl:concrete(Key)); %% false -> - Subst = t_subst(Key, Map), - t_sup(Subst, Subst). + t_subst(Key, Map). %% end. mk_var(Var) -> diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs b/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs index da498c225d..33d135048e 100644 --- a/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs @@ -1,5 +1,5 @@ my_callbacks_wrong.erl:26: The return type #state{parent::'undefined' | pid(),status::'closed' | 'init' | 'open',subscribe::[{pid(),integer()}],counter::integer()} in the specification of callback_init/1 is not a subtype of {'ok',_}, which is the expected return type for the callback of my_behaviour behaviour my_callbacks_wrong.erl:28: The inferred return type of callback_init/1 (#state{parent::'undefined' | pid(),status::'init',subscribe::[],counter::1}) has nothing in common with {'ok',_}, which is the expected return type for the callback of my_behaviour behaviour -my_callbacks_wrong.erl:30: The return type {'noreply',#state{parent::'undefined' | pid(),status::'closed' | 'init' | 'open',subscribe::[{pid(),integer()}],counter::integer()}} | {'reply',#state{parent::'undefined' | pid(),status::'closed' | 'init' | 'open',subscribe::[{pid(),integer()}],counter::integer()}} in the specification of callback_cast/3 is not a subtype of {'noreply',_}, which is the expected return type for the callback of my_behaviour behaviour +my_callbacks_wrong.erl:30: The return type {'reply',#state{parent::'undefined' | pid(),status::'closed' | 'init' | 'open',subscribe::[{pid(),integer()}],counter::integer()}} in the specification of callback_cast/3 is not a subtype of {'noreply',_}, which is the expected return type for the callback of my_behaviour behaviour my_callbacks_wrong.erl:39: The specified type for the 2nd argument of callback_call/3 (atom()) is not a supertype of pid(), which is expected type for this argument in the callback of the my_behaviour behaviour diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/vars_in_beh_spec b/lib/dialyzer/test/behaviour_SUITE_data/results/vars_in_beh_spec new file mode 100644 index 0000000000..5284e412f0 --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/results/vars_in_beh_spec @@ -0,0 +1,6 @@ + +vars_in_beh_spec.erl:3: Undefined callback function handle_call/3 (behaviour 'gen_server') +vars_in_beh_spec.erl:3: Undefined callback function handle_cast/2 (behaviour 'gen_server') +vars_in_beh_spec.erl:3: Undefined callback function handle_info/2 (behaviour 'gen_server') +vars_in_beh_spec.erl:3: Undefined callback function init/1 (behaviour 'gen_server') +vars_in_beh_spec.erl:3: Undefined callback function terminate/2 (behaviour 'gen_server') diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/vars_in_beh_spec.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/vars_in_beh_spec.erl new file mode 100644 index 0000000000..dc75b30d0e --- /dev/null +++ b/lib/dialyzer/test/behaviour_SUITE_data/src/vars_in_beh_spec.erl @@ -0,0 +1,10 @@ +-module(vars_in_beh_spec). + +-behaviour(gen_server). + +-export([code_change/3]). + +-spec code_change(_, State, _) -> {ok, State}. + +code_change(_, State, _) -> + {ok, State}. diff --git a/lib/dialyzer/test/small_SUITE_data/src/maybe_improper.erl b/lib/dialyzer/test/small_SUITE_data/src/maybe_improper.erl new file mode 100644 index 0000000000..1743d81493 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/maybe_improper.erl @@ -0,0 +1,7 @@ +-module(maybe_improper). + +-export([s/1]). + +-spec s(maybe_improper_list(X,Y)) -> {[X], maybe_improper_list(X,Y)}. +s(A) -> + lists:split(2,A). |