aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenrik Nord <[email protected]>2011-12-05 15:43:06 +0100
committerHenrik Nord <[email protected]>2011-12-05 15:43:10 +0100
commit22f51e7200b95773d55a60f89a78390dd86db58f (patch)
tree4d7b018ee91092796cefb29fd6958caf4ffbfd86
parentdc5c05208d2b4f9cc8ac0249f67583a682096bb8 (diff)
parent832ce20b01c6dcf19de169a6df54e11e9abb62c9 (diff)
downloadotp-22f51e7200b95773d55a60f89a78390dd86db58f.tar.gz
otp-22f51e7200b95773d55a60f89a78390dd86db58f.tar.bz2
otp-22f51e7200b95773d55a60f89a78390dd86db58f.zip
Merge branch 'sa/dialyzer-fixes'
* sa/dialyzer-fixes: Correct callback spec in application module Refine warning about callback specs with extra ranges Cleanup autoimport compiler directives Fix Dialyzer's warnings in typer Fix Dialyzer's warning for its own code Fix bug in Dialyzer's behaviours analysis Fix crash in Dialyzer OTP-9776
-rw-r--r--lib/dialyzer/src/dialyzer_behaviours.erl17
-rw-r--r--lib/dialyzer/src/dialyzer_cl.erl47
-rw-r--r--lib/dialyzer/src/dialyzer_typesig.erl3
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs2
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/vars_in_beh_spec6
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/vars_in_beh_spec.erl10
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/maybe_improper.erl7
-rw-r--r--lib/hipe/cerl/erl_types.erl37
-rw-r--r--lib/kernel/src/application.erl2
-rw-r--r--lib/typer/src/typer.erl4
10 files changed, 78 insertions, 57 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).
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 0ff827ac37..387690df43 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -2533,29 +2533,26 @@ findfirst(N1, N2, U1, B1, U2, B2) ->
t_subst(T, Dict) ->
case t_has_var(T) of
- true -> t_subst(T, Dict, fun(X) -> X end);
+ true -> t_subst_aux(T, Dict);
false -> T
end.
-spec subst_all_vars_to_any(erl_type()) -> erl_type().
subst_all_vars_to_any(T) ->
- case t_has_var(T) of
- true -> t_subst(T, dict:new(), fun(_) -> ?any end);
- false -> T
- end.
+ t_subst(T, dict:new()).
-t_subst(?var(Id) = V, Dict, Fun) ->
+t_subst_aux(?var(Id), Dict) ->
case dict:find(Id, Dict) of
- error -> Fun(V);
+ error -> ?any;
{ok, Type} -> Type
end;
-t_subst(?list(Contents, Termination, Size), Dict, Fun) ->
- case t_subst(Contents, Dict, Fun) of
+t_subst_aux(?list(Contents, Termination, Size), Dict) ->
+ case t_subst_aux(Contents, Dict) of
?none -> ?none;
NewContents ->
%% Be careful here to make the termination collapse if necessary.
- case t_subst(Termination, Dict, Fun) of
+ case t_subst_aux(Termination, Dict) of
?nil -> ?list(NewContents, ?nil, Size);
?any -> ?list(NewContents, ?any, Size);
Other ->
@@ -2563,17 +2560,17 @@ t_subst(?list(Contents, Termination, Size), Dict, Fun) ->
?list(NewContents, NewTermination, Size)
end
end;
-t_subst(?function(Domain, Range), Dict, Fun) ->
- ?function(t_subst(Domain, Dict, Fun), t_subst(Range, Dict, Fun));
-t_subst(?product(Types), Dict, Fun) ->
- ?product([t_subst(T, Dict, Fun) || T <- Types]);
-t_subst(?tuple(?any, ?any, ?any) = T, _Dict, _Fun) ->
+t_subst_aux(?function(Domain, Range), Dict) ->
+ ?function(t_subst_aux(Domain, Dict), t_subst_aux(Range, Dict));
+t_subst_aux(?product(Types), Dict) ->
+ ?product([t_subst_aux(T, Dict) || T <- Types]);
+t_subst_aux(?tuple(?any, ?any, ?any) = T, _Dict) ->
T;
-t_subst(?tuple(Elements, _Arity, _Tag), Dict, Fun) ->
- t_tuple([t_subst(E, Dict, Fun) || E <- Elements]);
-t_subst(?tuple_set(_) = TS, Dict, Fun) ->
- t_sup([t_subst(T, Dict, Fun) || T <- t_tuple_subtypes(TS)]);
-t_subst(T, _Dict, _Fun) ->
+t_subst_aux(?tuple(Elements, _Arity, _Tag), Dict) ->
+ t_tuple([t_subst_aux(E, Dict) || E <- Elements]);
+t_subst_aux(?tuple_set(_) = TS, Dict) ->
+ t_sup([t_subst_aux(T, Dict) || T <- t_tuple_subtypes(TS)]);
+t_subst_aux(T, _Dict) ->
T.
%%-----------------------------------------------------------------------------
diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl
index caac4d926c..c299fb085c 100644
--- a/lib/kernel/src/application.erl
+++ b/lib/kernel/src/application.erl
@@ -59,7 +59,7 @@
-callback start(StartType :: normal | {takeover, node()} | {failover, node()},
StartArgs :: term()) ->
- {ok, pid()} | {ok, pid(), State :: term()} | {error, Reason :: term}.
+ {'ok', pid()} | {'ok', pid(), State :: term()} | {'error', Reason :: term()}.
-callback stop(State :: term()) ->
term().
diff --git a/lib/typer/src/typer.erl b/lib/typer/src/typer.erl
index fd39b55dd4..6392f5765f 100644
--- a/lib/typer/src/typer.erl
+++ b/lib/typer/src/typer.erl
@@ -682,10 +682,10 @@ analyze_result(show_succ, Args, Analysis) ->
analyze_result(no_spec, Args, Analysis) ->
{Args, Analysis#analysis{no_spec = true}};
analyze_result({pa, Dir}, Args, Analysis) ->
- code:add_patha(Dir),
+ true = code:add_patha(Dir),
{Args, Analysis};
analyze_result({pz, Dir}, Args, Analysis) ->
- code:add_pathz(Dir),
+ true = code:add_pathz(Dir),
{Args, Analysis}.
%%--------------------------------------------------------------------