aboutsummaryrefslogtreecommitdiffstats
path: root/lib/dialyzer/test
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dialyzer/test')
-rw-r--r--lib/dialyzer/test/Makefile12
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options1
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs5
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/gen_event_incorrect_return2
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args8
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_missing_callbacks3
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour9
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour_old4
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/supervisor_incorrect_return2
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/undefined_callbacks2
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/vars_in_beh_spec6
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_behaviour.erl11
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_correct.erl59
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_wrong.erl61
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/custom_sup.erl37
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/gen_event_incorrect_return.erl33
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_incorrect_args.erl11
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_missing_callbacks.erl23
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_behaviour.erl13
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct.erl32
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct_2.erl38
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_wrong.erl26
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_behaviour.erl6
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_callback.erl15
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_args_callback.erl13
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_return_callback.erl15
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/missing_callback.erl10
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/supervisor_incorrect_return.erl17
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_beh_callback.erl13
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_behaviour.erl10
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/vars_in_beh_spec.erl10
-rw-r--r--lib/dialyzer/test/dialyzer_common.erl11
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/crash1
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/multiple_wrong_opaques2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/queue1
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/multiple_wrong_opaques.erl8
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/results/compiler1
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/results/inets33
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/results/mnesia4
-rw-r--r--lib/dialyzer/test/race_SUITE_data/results/ets_insert_args102
-rw-r--r--lib/dialyzer/test/race_SUITE_data/src/ets_insert_args10.erl19
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/cerl_hipeify2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes31
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy4
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy_28
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/inf_loop22
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/no_local_return3
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/port_info_test3
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash1
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/collapse_lists/a.erl9
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/collapse_lists/b.erl5
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes.erl267
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/deep_lc.erl14
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl14
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy_2.erl14
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/maybe_improper.erl7
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/maybe_servers.erl31
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/no_local_return.erl12
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/on_load.erl11
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/port_info_test.erl6
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/remote_tuple_set.erl8
-rw-r--r--lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options1
-rw-r--r--lib/dialyzer/test/underspecs_SUITE_data/results/remote9
-rw-r--r--lib/dialyzer/test/underspecs_SUITE_data/src/remote/remotes1.erl61
-rw-r--r--lib/dialyzer/test/underspecs_SUITE_data/src/remote/some_known_remote.erl5
-rw-r--r--lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_12
-rw-r--r--lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_20
-rw-r--r--lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_33
-rw-r--r--lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_1.erl18
-rw-r--r--lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_2.erl18
-rw-r--r--lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_3.erl16
71 files changed, 1137 insertions, 37 deletions
diff --git a/lib/dialyzer/test/Makefile b/lib/dialyzer/test/Makefile
index 47deb17f1d..9f8a3f1194 100644
--- a/lib/dialyzer/test/Makefile
+++ b/lib/dialyzer/test/Makefile
@@ -25,10 +25,10 @@ RELSYSDIR = $(RELEASE_PATH)/dialyzer_test
include $(ERL_TOP)/make/otp_release_targets.mk
release_tests_spec:
- $(INSTALL_DIR) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- $(INSTALL_DATA) $(AUXILIARY_FILES) $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
- cd $(RELSYSDIR);\
- erl -make;\
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(AUXILIARY_FILES) "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ cd "$(RELSYSDIR)";\
+ erlc dialyzer_common.erl file_utils.erl;\
erl -noshell -run dialyzer_common create_all_suites -s erlang halt
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options b/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options
new file mode 100644
index 0000000000..50991c9bc5
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options
@@ -0,0 +1 @@
+{dialyzer_options, []}.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs b/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs
new file mode 100644
index 0000000000..33d135048e
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs
@@ -0,0 +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 {'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/gen_event_incorrect_return b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_event_incorrect_return
new file mode 100644
index 0000000000..e646eea383
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_event_incorrect_return
@@ -0,0 +1,2 @@
+
+gen_event_incorrect_return.erl:16: The inferred return type of init/1 ('error') has nothing in common with {'error',_} | {'ok',_} | {'ok',_,'hibernate'}, which is the expected return type for the callback of gen_event behaviour
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args
new file mode 100644
index 0000000000..3e98da785f
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args
@@ -0,0 +1,8 @@
+
+gen_server_incorrect_args.erl:3: Undefined callback function code_change/3 (behaviour 'gen_server')
+gen_server_incorrect_args.erl:3: Undefined callback function handle_cast/2 (behaviour 'gen_server')
+gen_server_incorrect_args.erl:3: Undefined callback function handle_info/2 (behaviour 'gen_server')
+gen_server_incorrect_args.erl:3: Undefined callback function init/1 (behaviour 'gen_server')
+gen_server_incorrect_args.erl:3: Undefined callback function terminate/2 (behaviour 'gen_server')
+gen_server_incorrect_args.erl:7: The inferred return type of handle_call/3 ({'no'} | {'ok'}) has nothing in common with {'noreply',_} | {'noreply',_,'hibernate' | 'infinity' | non_neg_integer()} | {'reply',_,_} | {'stop',_,_} | {'reply',_,_,'hibernate' | 'infinity' | non_neg_integer()} | {'stop',_,_,_}, which is the expected return type for the callback of gen_server behaviour
+gen_server_incorrect_args.erl:7: The inferred type for the 2nd argument of handle_call/3 ('boo' | 'foo') is not a supertype of {pid(),_}, which is expected type for this argument in the callback of the gen_server behaviour
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_missing_callbacks b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_missing_callbacks
new file mode 100644
index 0000000000..5e0ed5fd27
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_missing_callbacks
@@ -0,0 +1,3 @@
+
+gen_server_missing_callbacks.erl:3: Undefined callback function handle_cast/2 (behaviour 'gen_server')
+gen_server_missing_callbacks.erl:3: Undefined callback function handle_info/2 (behaviour 'gen_server')
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour
new file mode 100644
index 0000000000..8cecabccaa
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour
@@ -0,0 +1,9 @@
+
+sample_callback_wrong.erl:16: The inferred return type of sample_callback_2/0 (42) has nothing in common with atom(), which is the expected return type for the callback of sample_behaviour behaviour
+sample_callback_wrong.erl:17: The inferred return type of sample_callback_3/0 ('fair') has nothing in common with 'fail' | {'ok',1..255}, which is the expected return type for the callback of sample_behaviour behaviour
+sample_callback_wrong.erl:18: The inferred return type of sample_callback_4/1 ('fail') has nothing in common with 'ok', which is the expected return type for the callback of sample_behaviour behaviour
+sample_callback_wrong.erl:20: The inferred return type of sample_callback_5/1 (string()) has nothing in common with 'fail' | 'ok', which is the expected return type for the callback of sample_behaviour behaviour
+sample_callback_wrong.erl:20: The inferred type for the 1st argument of sample_callback_5/1 (atom()) is not a supertype of 1..255, which is expected type for this argument in the callback of the sample_behaviour behaviour
+sample_callback_wrong.erl:22: The inferred return type of sample_callback_6/3 ({'okk',number()}) has nothing in common with 'fail' | {'ok',1..255}, which is the expected return type for the callback of sample_behaviour behaviour
+sample_callback_wrong.erl:22: The inferred type for the 3rd argument of sample_callback_6/3 (atom()) is not a supertype of string(), which is expected type for this argument in the callback of the sample_behaviour behaviour
+sample_callback_wrong.erl:4: Undefined callback function sample_callback_1/0 (behaviour 'sample_behaviour')
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour_old b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour_old
new file mode 100644
index 0000000000..f0181bb59c
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour_old
@@ -0,0 +1,4 @@
+
+incorrect_args_callback.erl:12: The inferred type for the 2nd argument of bar/2 ('yes') is not a supertype of [any()], which is expected type for this argument in the callback of the correct_behaviour behaviour
+incorrect_return_callback.erl:9: The inferred return type of foo/0 ('error') has nothing in common with 'no' | 'yes', which is the expected return type for the callback of correct_behaviour behaviour
+missing_callback.erl:5: Undefined callback function foo/0 (behaviour 'correct_behaviour')
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/supervisor_incorrect_return b/lib/dialyzer/test/behaviour_SUITE_data/results/supervisor_incorrect_return
new file mode 100644
index 0000000000..e89caf3cf7
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/supervisor_incorrect_return
@@ -0,0 +1,2 @@
+
+supervisor_incorrect_return.erl:14: The inferred return type of init/1 ({'ok',{{'one_against_one',0,1},[{_,_,_,_,_,_},...]}}) has nothing in common with 'ignore' | {'ok',{{'one_for_all',non_neg_integer(),non_neg_integer()} | {'one_for_one',non_neg_integer(),non_neg_integer()} | {'rest_for_one',non_neg_integer(),non_neg_integer()} | {'simple_one_for_one',non_neg_integer(),non_neg_integer()},[{_,{atom() | tuple(),atom(),'undefined' | [any()]},'permanent' | 'temporary' | 'transient','brutal_kill' | 'infinity' | non_neg_integer(),'supervisor' | 'worker','dynamic' | [atom() | tuple()]}]}}, which is the expected return type for the callback of supervisor behaviour
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/undefined_callbacks b/lib/dialyzer/test/behaviour_SUITE_data/results/undefined_callbacks
new file mode 100644
index 0000000000..7147ffc750
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/undefined_callbacks
@@ -0,0 +1,2 @@
+
+undefined_beh_callback.erl:5: Callback info about the undefined_behaviour behaviour is not available
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/callbacks_and_specs/my_behaviour.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_behaviour.erl
new file mode 100644
index 0000000000..c4e5203448
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_behaviour.erl
@@ -0,0 +1,11 @@
+-module(my_behaviour).
+
+-callback callback_init(Parent :: pid()) -> {'ok', State::term()}.
+
+-callback callback_cast(State::term(), From::pid(), Msg::term()) ->
+ {'noreply', NewState::term()}.
+
+-callback callback_call(State::term(), From::pid(), Msg::term()) ->
+ {'reply', NewState::term(), Reply::term()}.
+
+-callback callback_exit(State::term()) -> 'ok'.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_correct.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_correct.erl
new file mode 100644
index 0000000000..041b4ac56c
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_correct.erl
@@ -0,0 +1,59 @@
+-module(my_callbacks_correct).
+
+-export([
+ callback_init/1
+ , callback_call/3
+ , callback_cast/3
+ , callback_exit/1
+ ]).
+
+-record(state, {
+ parent :: pid(),
+ status = init :: 'init' | 'open' | 'closed',
+ subscribe = [] :: list({pid(), integer()}),
+ counter = 1 :: integer()
+ }).
+
+-type state() :: #state{}.
+
+-type cast_message() :: 'open' | 'closed'.
+
+-type call_message() :: 'subscribe' | 'unsubscribe'.
+-type call_reply() :: 'accepted' | 'rejected'.
+
+-spec callback_init(Parent::pid()) -> {'ok', state()}.
+
+callback_init(Parent) ->
+ {ok, #state{parent = Parent}}.
+
+-spec callback_cast(state(), pid(), cast_message()) -> {'noreply', state()}.
+
+callback_cast(#state{parent = Pid} = State, Pid, Message)
+ when Message =:= 'open'; Message =:= 'close' ->
+ {noreply, State#state{status = Message}};
+callback_cast(State, _Pid, _Message) ->
+ {noreply, State}.
+
+-spec callback_call(state(), pid(), call_message()) ->
+ {'reply', state(), call_reply()}.
+
+callback_call(#state{status = open, subscribe = Subscribers} = State,
+ Pid, Message)
+ when Message =:= 'subscribe';
+ Message =:= 'unsubscribe' ->
+ NewState =
+ case Message of
+ subscribe ->
+ N = State#state.counter,
+ State#state{subscribe = [{Pid, N}|Subscribers], counter = N+1};
+ unsubscribe ->
+ State#state{subscribe = lists:keydelete(Pid, 1, Subscribers)}
+ end,
+ {reply, NewState, accepted};
+callback_call(State, _Pid, _Message) ->
+ {reply, State, rejected}.
+
+-spec callback_exit(state()) -> 'ok'.
+
+callback_exit(_State) ->
+ ok.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_wrong.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_wrong.erl
new file mode 100644
index 0000000000..0459622dc1
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_wrong.erl
@@ -0,0 +1,61 @@
+-module(my_callbacks_wrong).
+
+-export([
+ callback_init/1
+ , callback_call/3
+ , callback_cast/3
+ , callback_exit/1
+ ]).
+
+-behaviour(my_behaviour).
+
+-record(state, {
+ parent :: pid(),
+ status = init :: 'init' | 'open' | 'closed',
+ subscribe = [] :: list({pid(), integer()}),
+ counter = 1 :: integer()
+ }).
+
+-type state() :: #state{}.
+
+-type cast_message() :: 'open' | 'closed'.
+
+-type call_message() :: 'subscribe' | 'unsubscribe'.
+-type call_reply() :: 'accepted' | 'rejected'.
+
+-spec callback_init(Parent::pid()) -> state(). %% Wrong return spec
+
+callback_init(Parent) -> #state{parent = Parent}. %% Wrong return
+
+-spec callback_cast(state(), pid() | atom(), cast_message()) ->
+ {'noreply' | 'reply', state()}. %% More generic spec
+
+callback_cast(#state{parent = Pid} = State, Pid, Message)
+ when Message =:= 'open'; Message =:= 'close' ->
+ {noreply, State#state{status = Message}};
+callback_cast(State, _Pid, _Message) ->
+ {noreply, State}.
+
+-spec callback_call(state(), atom(), call_message()) -> %% Wrong arg spec
+ {'reply', state(), call_reply()}.
+
+callback_call(#state{status = open, subscribe = Subscribers} = State,
+ Pid, Message)
+ when Message =:= 'subscribe';
+ Message =:= 'unsubscribe' ->
+ NewState =
+ case Message of
+ subscribe ->
+ N = State#state.counter,
+ State#state{subscribe = [{Pid, N}|Subscribers], counter = N+1};
+ unsubscribe ->
+ State#state{subscribe = lists:keydelete(Pid, 1, Subscribers)}
+ end,
+ {reply, NewState, accepted};
+callback_call(State, _Pid, _Message) ->
+ {reply, State, rejected}.
+
+-spec callback_exit(state()) -> ok.
+
+callback_exit(_State) ->
+ ok.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/custom_sup.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/custom_sup.erl
new file mode 100644
index 0000000000..8ec84d798f
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/custom_sup.erl
@@ -0,0 +1,37 @@
+%%% Dialyzer was giving a warning with this input because of a bug in the
+%%% substitution of remote types in specs. Remote types in the first element of
+%%% a tuple would not update the tuple's tag set and we could end up with a
+%%% non-normalized representation.
+%%%
+%%% Reported by Damian Dobroczyński on 29/02/2012
+
+-module(custom_sup).
+
+-behavior(supervisor).
+
+-export([init/1]).
+
+-spec init(atom()) ->
+ {ok, {{supervisor:strategy(), non_neg_integer(), non_neg_integer()},
+ [supervisor:child_spec()]}} | ignore.
+
+init(StorageName) ->
+ Strategy = {one_for_all, 100, 1},
+ %% get application-wide storage parameters
+ case application:get_env(storage) of
+ undefined ->
+ ignore;
+ {ok, Storage} ->
+ BackendId = proplists:get_value(backend, Storage),
+ BackendArgs = proplists:get_value(args, Storage),
+ if
+ (BackendId =:= undefined) orelse (BackendArgs =:= undefined) ->
+ ignore;
+ true ->
+ {ok, {Strategy,
+ [{id1, {a_module, start_link, []},
+ permanent, 5000, worker, [a_module]},
+ {id2, {another_module, start_link, []},
+ permanent, 5000, worker, [another_module]}]}}
+ end
+ end.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/gen_event_incorrect_return.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_event_incorrect_return.erl
new file mode 100644
index 0000000000..f5ccf7f8c4
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_event_incorrect_return.erl
@@ -0,0 +1,33 @@
+-module(gen_event_incorrect_return).
+
+-behaviour(gen_event).
+
+-export([start_link/0, add_handler/0]).
+
+-export([init/1, handle_event/2, handle_call/2,
+ handle_info/2, terminate/2, code_change/3]).
+
+start_link() ->
+ gen_event:start_link({local, myserver}).
+
+add_handler() ->
+ gen_event:add_handler(myserver, ?MODULE, []).
+
+init([]) ->
+ error.
+
+handle_event(_Event, State) ->
+ {ok, State}.
+
+handle_call(_Request, State) ->
+ Reply = ok,
+ {ok, Reply, State}.
+
+handle_info(_Info, State) ->
+ {ok, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_incorrect_args.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_incorrect_args.erl
new file mode 100644
index 0000000000..df04dff80d
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_incorrect_args.erl
@@ -0,0 +1,11 @@
+-module(gen_server_incorrect_args).
+
+-behaviour(gen_server).
+
+-export([handle_call/3]).
+
+handle_call(_Request, From, _State) ->
+ case From of
+ 'boo' -> {'ok'};
+ 'foo' -> {'no'}
+ end.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_missing_callbacks.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_missing_callbacks.erl
new file mode 100644
index 0000000000..760466fdac
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_missing_callbacks.erl
@@ -0,0 +1,23 @@
+-module(gen_server_missing_callbacks).
+
+-behaviour(gen_server).
+
+-export([start_link/0]).
+
+-export([init/1, handle_call/3, terminate/2, code_change/3]).
+
+start_link() ->
+ gen_server:start_link({local, myserver}, ?MODULE, [], []).
+
+init([]) ->
+ ignore.
+
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_behaviour.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_behaviour.erl
new file mode 100644
index 0000000000..116980986b
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_behaviour.erl
@@ -0,0 +1,13 @@
+-module(sample_behaviour).
+
+-type custom() :: 1..42.
+
+-callback sample_callback_1() -> term().
+-callback sample_callback_2() -> atom().
+-callback sample_callback_3() -> {'ok', custom()} | 'fail'.
+
+-callback sample_callback_4(term()) -> 'ok'.
+-callback sample_callback_5(custom()) -> 'ok' | 'fail'.
+
+-callback sample_callback_6(custom(), custom(), string()) ->
+ {'ok', custom()} | 'fail'.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct.erl
new file mode 100644
index 0000000000..ab0378e6f0
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct.erl
@@ -0,0 +1,32 @@
+-module(sample_callback_correct).
+
+-behaviour(sample_behaviour).
+
+-export([
+ sample_callback_1/0,
+ sample_callback_2/0,
+ sample_callback_3/0,
+ sample_callback_4/1,
+ sample_callback_5/1,
+ sample_callback_6/3
+ ]).
+
+sample_callback_1() -> 42. % This is a valid return.
+sample_callback_2() -> foo. % This is a valid return.
+sample_callback_3() -> {ok, 17}. % This is a valid return.
+sample_callback_4(Input) ->
+ put(mine, Input+1), % This is valid handling of the input
+ ok. % This is a valid return.
+sample_callback_5(Input) ->
+ case Input - 1 < 22 of % This is valid handling of the input
+ true -> ok; % This is a valid return.
+ false -> fail % This is a valid return.
+ end.
+sample_callback_6(OldNr, NewNr, Reason) ->
+ Diff = NewNr - OldNr, % This is valid handling of the input
+ Msg = string:join(["Reason: ", Reason], ","), % This is valid handling of the input
+ case Diff > 0 of
+ true -> put(mine, {NewNr, Msg}),
+ {ok, NewNr}; % This is a valid return.
+ false -> fail % This is a valid return.
+ end.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct_2.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct_2.erl
new file mode 100644
index 0000000000..c218174e58
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct_2.erl
@@ -0,0 +1,38 @@
+-module(sample_callback_correct_2).
+
+-behaviour(sample_behaviour).
+
+-export([
+ sample_callback_1/0,
+ sample_callback_2/0,
+ sample_callback_3/0,
+ sample_callback_4/1,
+ sample_callback_5/1,
+ sample_callback_6/3,
+ common_infrastructure/1
+ ]).
+
+sample_callback_1() -> 42. % This is a valid return.
+sample_callback_2() -> halt(). % Crashes are also allowed.
+sample_callback_3() -> {ok, 17}. % This is a valid return.
+sample_callback_4(Input) ->
+ case Input of
+ 1 -> common_infrastructure(Input); % This is 'correct' input for
+ _ -> ok % common_infrastructure.
+ end.
+sample_callback_5(Input) ->
+ case get(Input) of % This is valid handling of a more generic input
+ true -> ok; % This is a valid return.
+ false -> fail % This is a valid return.
+ end.
+sample_callback_6(OldNr, NewNr, Reason) ->
+ Diff = NewNr - OldNr, % This is valid handling of the input
+ Msg = string:join(["Reason: ", Reason], ","), % This is valid handling of the input
+ case Diff > 0 of
+ true -> put(mine, {NewNr, Msg}),
+ {ok, NewNr}; % This is a valid return.
+ false -> fail % This is a valid return.
+ end.
+
+common_infrastructure( 1) -> 'ok';
+common_infrastructure(42) -> 'fail'.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_wrong.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_wrong.erl
new file mode 100644
index 0000000000..430494c48c
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_wrong.erl
@@ -0,0 +1,26 @@
+-module(sample_callback_wrong).
+
+%% This attribute uses the american spelling of 'behaviour'.
+-behavior(sample_behaviour).
+
+-export([
+% sample_callback_1/0,
+ sample_callback_2/0,
+ sample_callback_3/0,
+ sample_callback_4/1,
+ sample_callback_5/1,
+ sample_callback_6/3
+ ]).
+
+% sample_callback_1() -> 41. % We can't really break this contract so: missing!
+sample_callback_2() -> 42. % This is not an atom().
+sample_callback_3() -> fair. % This is probably a typo.
+sample_callback_4(_) -> % We cannot break the input.
+ fail. % We can definitely return a wrong value however. :)
+sample_callback_5(Input) -> % Input is treated as an atom, result is a list.
+ atom_to_list(Input). % Both violate the contract.
+sample_callback_6(OldNr, NewNr, Reason) ->
+ Diff = NewNr - OldNr, % This is valid handling of the input
+ %% Reason should have been treated as a string.
+ Msg = string:join(["Reason: ", atom_to_list(Reason)], ","),
+ {okk, NewNr}. %% This, too, is a typo.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_behaviour.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_behaviour.erl
new file mode 100644
index 0000000000..90ce590997
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_behaviour.erl
@@ -0,0 +1,6 @@
+%%% This is a behaviour with info about its calllbacks.
+
+-module(correct_behaviour).
+
+-callback foo() -> yes | no.
+-callback bar({atom(),_},[_]) -> term().
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_callback.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_callback.erl
new file mode 100644
index 0000000000..8f254520ab
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_callback.erl
@@ -0,0 +1,15 @@
+%%% This is a correct callback module for the correct_behaviour.
+
+-module(correct_callback).
+
+-behaviour(correct_behaviour).
+
+-export([foo/0, bar/2]).
+
+foo() ->
+ yes.
+
+bar({'query', 'boo'}, _Any) ->
+ no;
+bar({'reply', [_R]}, [1,2,3]) ->
+ yes.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_args_callback.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_args_callback.erl
new file mode 100644
index 0000000000..68fc60d418
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_args_callback.erl
@@ -0,0 +1,13 @@
+%%% This is a correct callback module for the correct_behaviour.
+
+-module(incorrect_args_callback).
+
+-behaviour(correct_behaviour).
+
+-export([foo/0, bar/2]).
+
+foo() ->
+ yes.
+
+bar({'reply', _Any}, yes) -> %% Should be a tuple and a list.
+ yes.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_return_callback.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_return_callback.erl
new file mode 100644
index 0000000000..9ff920cdd0
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_return_callback.erl
@@ -0,0 +1,15 @@
+%%% This is a correct callback module for the correct_behaviour.
+
+-module(incorrect_return_callback).
+
+-behaviour(correct_behaviour).
+
+-export([foo/0, bar/2]).
+
+foo() ->
+ error. %% Should be 'yes' or 'no'.
+
+bar({'query', 'boo'}, _Any) ->
+ no;
+bar({'reply', [_R]}, [1,2,3]) ->
+ yes.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/missing_callback.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/missing_callback.erl
new file mode 100644
index 0000000000..e6c5306839
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/missing_callback.erl
@@ -0,0 +1,10 @@
+%%% This is a correct callback module for the correct_behaviour.
+
+-module(missing_callback).
+
+-behaviour(correct_behaviour).
+
+-export([bar/2]).
+
+bar({'reply', _Any}, []) ->
+ yes.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/supervisor_incorrect_return.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/supervisor_incorrect_return.erl
new file mode 100644
index 0000000000..616a9073ae
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/supervisor_incorrect_return.erl
@@ -0,0 +1,17 @@
+-module(supervisor_incorrect_return).
+
+-behaviour(supervisor).
+
+-export([start_link/0]).
+
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+start_link() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+init([]) ->
+ AChild = {'AName',{'AModule',start_link,[]},
+ permanent,2000,worker,['AModule']},
+ {ok,{{one_against_one,0,1}, [AChild]}}.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_beh_callback.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_beh_callback.erl
new file mode 100644
index 0000000000..8223225b4b
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_beh_callback.erl
@@ -0,0 +1,13 @@
+%%% This is a correct callback module for the correct_behaviour.
+
+-module(undefined_beh_callback).
+
+-behaviour(undefined_behaviour).
+
+-export([foo/0, bar/2]).
+
+foo() ->
+ yes.
+
+bar({'reply', _Any}, yes) ->
+ yes.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_behaviour.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_behaviour.erl
new file mode 100644
index 0000000000..fb3d4c5e03
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_behaviour.erl
@@ -0,0 +1,10 @@
+%%% This is a behaviour with undefined info about its calllbacks.
+
+-module(undefined_behaviour).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{foo, 0}, {bar, 2}];
+behaviour_info(_Other) ->
+ undefined.
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/dialyzer_common.erl b/lib/dialyzer/test/dialyzer_common.erl
index 51766a4604..d2b1026c06 100644
--- a/lib/dialyzer/test/dialyzer_common.erl
+++ b/lib/dialyzer/test/dialyzer_common.erl
@@ -216,10 +216,13 @@ get_suites(Dir) ->
end.
suffix(String, Suffix) ->
- Index = string:rstr(String, Suffix),
- case string:substr(String, Index) =:= Suffix of
- true -> {yes, string:sub_string(String,1,Index-1)};
- false -> no
+ case string:rstr(String, Suffix) of
+ 0 -> no;
+ Index ->
+ case string:substr(String, Index) =:= Suffix of
+ true -> {yes, string:sub_string(String,1,Index-1)};
+ false -> no
+ end
end.
-spec create_suite(string()) -> 'ok'.
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/crash b/lib/dialyzer/test/opaque_SUITE_data/results/crash
index 6bdd934169..1ddae5149f 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/crash
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/crash
@@ -1,5 +1,4 @@
-crash_1.erl:42: The specification for crash_1:empty/0 states that the function might also return crash_1:targetlist() but the inferred return is none()
crash_1.erl:45: Record construction #targetlist{list::[]} violates the declared type of field list::'undefined' | crash_1:target()
crash_1.erl:48: The call crash_1:get_using_branch2(Branch::maybe_improper_list(),L::'undefined' | crash_1:target()) contains an opaque term as 2nd argument when terms of different types are expected in these positions
crash_1.erl:50: The pattern <_Branch, []> can never match the type <maybe_improper_list(),'undefined' | crash_1:target()>
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/multiple_wrong_opaques b/lib/dialyzer/test/opaque_SUITE_data/results/multiple_wrong_opaques
new file mode 100644
index 0000000000..18ece8820c
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/multiple_wrong_opaques
@@ -0,0 +1,2 @@
+
+multiple_wrong_opaques.erl:5: Invalid type specification for function multiple_wrong_opaques:weird/1. The success typing is ('gazonk') -> 42
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/queue b/lib/dialyzer/test/opaque_SUITE_data/results/queue
index 59ce33f098..c3f04ea64d 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/queue
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/queue
@@ -5,6 +5,7 @@ queue_use.erl:27: The attempt to match a term of type queue() against the patter
queue_use.erl:33: Attempt to test for equality between a term of type {[42,...],[]} and a term of opaque type queue()
queue_use.erl:36: The attempt to match a term of type queue() against the pattern {F, _R} breaks the opaqueness of the term
queue_use.erl:40: The call queue:out({[42,...],[]}) does not have an opaque term of type queue() as 1st argument
+queue_use.erl:48: The call queue_use:add_unique(42,#db{p::[],q::queue()}) contains an opaque term as 2nd argument when terms of different types are expected in these positions
queue_use.erl:51: The call queue_use:is_in_queue(E::42,DB::#db{p::[],q::queue()}) contains an opaque term as 2nd argument when terms of different types are expected in these positions
queue_use.erl:56: The attempt to match a term of type #db{p::[],q::queue()} against the pattern {'db', _, {L1, L2}} breaks the opaqueness of queue()
queue_use.erl:62: The call queue_use:tuple_queue({42,'gazonk'}) does not have a term of type {_,queue()} (with opaque subterms) as 1st argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/multiple_wrong_opaques.erl b/lib/dialyzer/test/opaque_SUITE_data/src/multiple_wrong_opaques.erl
new file mode 100644
index 0000000000..9e695cec1d
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/multiple_wrong_opaques.erl
@@ -0,0 +1,8 @@
+-module(multiple_wrong_opaques).
+
+-export([weird/1]).
+
+-spec weird(dict() | gb_tree()) -> 42.
+
+weird(gazonk) -> 42.
+
diff --git a/lib/dialyzer/test/options1_SUITE_data/results/compiler b/lib/dialyzer/test/options1_SUITE_data/results/compiler
index e82087ae86..6399e3e36b 100644
--- a/lib/dialyzer/test/options1_SUITE_data/results/compiler
+++ b/lib/dialyzer/test/options1_SUITE_data/results/compiler
@@ -20,6 +20,7 @@ cerl_inline.erl:2333: The pattern 'true' can never match the type 'false'
cerl_inline.erl:2355: The pattern 'true' can never match the type 'false'
cerl_inline.erl:238: The pattern 'true' can never match the type 'false'
cerl_inline.erl:2436: Function filename/1 will never be called
+cerl_inline.erl:244: Function counter_stats/0 will never be called
cerl_inline.erl:2700: The pattern 'true' can never match the type 'false'
cerl_inline.erl:2730: The pattern <{F, L, D}, Vs> can never match the type <[1..255,...],[any()]>
cerl_inline.erl:2738: The pattern <{F, L, D}, Vs> can never match the type <[1..255,...],[any()]>
diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/inets b/lib/dialyzer/test/r9c_SUITE_data/results/inets
index 0177dcc88c..773525eb7f 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/results/inets
+++ b/lib/dialyzer/test/r9c_SUITE_data/results/inets
@@ -3,21 +3,16 @@ ftp.erl:1243: The pattern {'ok', {N, Bytes}} can never match the type 'eof' | {'
ftp.erl:640: The pattern {'closed', _Why} can never match the type 'perm_fname_not_allowed' | 'perm_neg_compl' | 'perm_no_space' | 'pos_compl' | 'pos_interm' | 'pos_interm_acct' | 'trans_neg_compl' | 'trans_no_space' | {'error' | 'perm_fname_not_allowed' | 'perm_neg_compl' | 'perm_no_space' | 'pos_compl' | 'pos_interm' | 'pos_interm_acct' | 'pos_prel' | 'trans_neg_compl' | 'trans_no_space',atom() | [any()] | {'invalid_server_response',[any(),...]}}
http.erl:117: The pattern {'error', Reason} can never match the type #req_headers{connection::[45 | 97 | 101 | 105 | 107 | 108 | 112 | 118,...],content_length::[48,...],other::[{_,_}]}
http.erl:138: Function close_session/2 will never be called
-http_lib.erl:286: The call http_lib:close('ip_comm' | {'ssl',_},port() | {'sslsocket',_,_}) will never return since it differs in the 1st argument from the success typing arguments: ('http' | 'https',port() | {'sslsocket',_,pid() | {_,{'config',_,_,_,_,{_,_,_,_}}} | {'sslsocket',_,pid() | {'sslsocket',_,pid() | {_,_,_}}}})
-http_lib.erl:415: The pattern 61 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}
-http_lib.erl:417: The pattern 59 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}
-http_lib.erl:420: The pattern 13 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}
-http_lib.erl:424: The variable _ can never match since previous clauses completely covered the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}
-http_lib.erl:428: Function read_chunk_ext_val/6 will never be called
-http_lib.erl:444: The pattern 10 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}
-http_lib.erl:552: Call to missing or unexported function ssl:accept/2
+http_lib.erl:286: The call http_lib:close('ip_comm' | {'ssl',_},any()) will never return since it differs in the 1st argument from the success typing arguments: ('http' | 'https',any())
+http_lib.erl:424: The variable _ can never match since previous clauses completely covered the type any()
+http_lib.erl:438: The variable _ can never match since previous clauses completely covered the type any()
http_lib.erl:99: Function getHeaderValue/2 will never be called
httpc_handler.erl:660: Function exit_session_ok/2 has no local return
+httpc_handler.erl:676: Function format_time/0 will never be called
httpc_manager.erl:145: The pattern {ErrorReply, State2} can never match the type {{'ok',number()},number(),#state{reqid::number()}}
httpc_manager.erl:160: The pattern {ErrorReply, State2} can never match the type {{'ok',number()},number(),#state{reqid::number()}}
httpc_manager.erl:478: The pattern {'error', Reason} can never match the type 'ok' | {number(),#session{clientclose::boolean(),pipeline::[],quelength::1}}
httpc_manager.erl:490: The pattern {'error', Reason} can never match the type 'ok' | {number(),#session{clientclose::boolean(),pipeline::[],quelength::1}}
-httpd.erl:583: The pattern <{'error', Reason}, _Fd, SoFar> can never match the type <[any()],pid(),[[any(),...]]>
httpd_acceptor.erl:105: The pattern {'error', Reason} can never match the type {'ok',pid()}
httpd_acceptor.erl:110: Function handle_connection_err/4 will never be called
httpd_acceptor.erl:168: Function report_error/2 will never be called
@@ -26,14 +21,10 @@ httpd_manager.erl:885: The pattern {'EXIT', Reason} can never match since previo
httpd_manager.erl:919: Function auth_status/1 will never be called
httpd_manager.erl:926: Function sec_status/1 will never be called
httpd_manager.erl:933: Function acceptor_status/1 will never be called
-httpd_request_handler.erl:374: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 66 | 98 | 100 | 103 | 105 | 111 | 116 | 121,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_},socket::port() | {'sslsocket',_,_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
-httpd_request_handler.erl:378: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_},socket::port() | {'sslsocket',_,_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
-httpd_request_handler.erl:401: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_},socket::port() | {'sslsocket',_,_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
-httpd_request_handler.erl:489: The variable Other can never match since previous clauses completely covered the type {'error',_} | {'ok','http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | {'http_request','DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),'*' | binary() | string() | {'abs_path',binary() | [any()]} | {'scheme',binary() | [any()],binary() | [any()]} | {'absoluteURI','http' | 'https',binary() | [any()],'undefined' | non_neg_integer(),binary() | [any()]},{non_neg_integer(),non_neg_integer()}} | {'http_response',{non_neg_integer(),non_neg_integer()},integer(),binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}}
-httpd_request_handler.erl:644: The call lists:reverse(Fields0::{'error',_} | {'ok',_}) will never return since it differs in the 1st argument from the success typing arguments: ([any()])
-httpd_request_handler.erl:645: Function will never be called
-httpd_socket.erl:129: Call to missing or unexported function ssl:accept/2
-httpd_socket.erl:49: The pattern {'ok', _} can never match the type {'error',_}
+httpd_request_handler.erl:374: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 66 | 98 | 100 | 103 | 105 | 111 | 116 | 121,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
+httpd_request_handler.erl:378: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
+httpd_request_handler.erl:401: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
+httpd_request_handler.erl:649: Guard test [{_,_}] =:= Trailers::nonempty_string() can never succeed
httpd_sup.erl:63: The variable Else can never match since previous clauses completely covered the type {'error',_} | {'ok',[any()],_,_}
httpd_sup.erl:88: The pattern {'error', Reason} can never match the type {'ok',_,_}
httpd_sup.erl:92: The variable Else can never match since previous clauses completely covered the type {'ok',_,_}
@@ -48,10 +39,10 @@ mod_dir.erl:72: The pattern {'error', Reason} can never match the type {'ok',[[[
mod_get.erl:135: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | [any()] | char()]>
mod_head.erl:80: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | [any()] | char()]>
mod_htaccess.erl:460: The pattern {'error', BadData} can never match the type {'ok',_}
-mod_include.erl:193: The pattern {_, Name, {[], []}} can never match the type {[any()],[any()],string()}
-mod_include.erl:195: The pattern {_, Name, {PathInfo, []}} can never match the type {[any()],[any()],string()}
-mod_include.erl:197: The pattern {_, Name, {PathInfo, QueryString}} can never match the type {[any()],[any()],string()}
-mod_include.erl:201: The variable Gurka can never match since previous clauses completely covered the type {[any()],[any()],string()}
+mod_include.erl:193: The pattern {_, Name, {[], []}} can never match the type {[any()],[any()],maybe_improper_list()}
+mod_include.erl:195: The pattern {_, Name, {PathInfo, []}} can never match the type {[any()],[any()],maybe_improper_list()}
+mod_include.erl:197: The pattern {_, Name, {PathInfo, QueryString}} can never match the type {[any()],[any()],maybe_improper_list()}
+mod_include.erl:201: The variable Gurka can never match since previous clauses completely covered the type {[any()],[any()],maybe_improper_list()}
mod_include.erl:692: The pattern <{'read', Reason}, Info, Path> can never match the type <{'open',atom()},#mod{},atom() | binary() | [atom() | [any()] | char()]>
mod_include.erl:706: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | [any()] | char()]>
mod_include.erl:716: Function read_error/3 will never be called
diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/mnesia b/lib/dialyzer/test/r9c_SUITE_data/results/mnesia
index 2be71ac7d7..b397d37523 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/results/mnesia
+++ b/lib/dialyzer/test/r9c_SUITE_data/results/mnesia
@@ -2,6 +2,7 @@
mnesia.erl:1319: Guard test size(Spec::[{_,_,_},...]) can never succeed
mnesia.erl:1498: The call mnesia:bad_info_reply(Tab::atom(),Item::'type') will never return since it differs in the 2nd argument from the success typing arguments: (atom(),'memory' | 'size')
mnesia.erl:331: Function mod2abs/1 has no local return
+mnesia_backup.erl:49: Callback info about the mnesia_backup behaviour is not available
mnesia_bup.erl:111: The created fun has no local return
mnesia_bup.erl:574: Function fallback_receiver/2 has no local return
mnesia_bup.erl:967: Function uninstall_fallback_master/2 has no local return
@@ -12,9 +13,12 @@ mnesia_controller.erl:1679: The pattern {'stop', Reason, Reply, State2} can neve
mnesia_controller.erl:1685: The pattern {'noreply', State2, _Timeout} can never match the type {'reply',_,_}
mnesia_event.erl:77: The pattern 'remove_handler' can never match the type {'ok',_}
mnesia_event.erl:79: The pattern {'swap_handler', Args1, State1, Mod2, Args2} can never match the type {'ok',_}
+mnesia_frag.erl:26: Callback info about the mnesia_access behaviour is not available
mnesia_frag.erl:294: The call mnesia_frag:remote_collect(Ref::reference(),{'error',_},[],OldSelectFun::fun(() -> [any()])) will never return since it differs in the 2nd argument from the success typing arguments: (reference(),'ok',[any()],fun(() -> [any()]))
mnesia_frag.erl:304: The call mnesia_frag:remote_collect(Ref::reference(),{'error',{'node_not_running',_}},[],OldSelectFun::fun(() -> [any()])) will never return since it differs in the 2nd argument from the success typing arguments: (reference(),'ok',[any()],fun(() -> [any()]))
mnesia_frag.erl:312: The call mnesia_frag:remote_collect(Ref::reference(),LocalRes::{'error',_},[],OldSelectFun::fun(() -> [any()])) will never return since it differs in the 2nd argument from the success typing arguments: (reference(),'ok',[any()],fun(() -> [any()]))
+mnesia_frag_hash.erl:24: Callback info about the mnesia_frag_hash behaviour is not available
+mnesia_frag_old_hash.erl:23: Callback info about the mnesia_frag_hash behaviour is not available
mnesia_index.erl:52: The call mnesia_lib:other_val(Var::{_,'commit_work' | 'index' | 'setorbag' | 'storage_type' | {'index',_}},_ReASoN_::any()) will never return since it differs in the 1st argument from the success typing arguments: ({_,'active_replicas' | 'where_to_read' | 'where_to_write'},any())
mnesia_lib.erl:1028: The pattern {'EXIT', Reason} can never match the type [any()] | {'error',_}
mnesia_lib.erl:957: The pattern {'ok', {0, _}} can never match the type 'eof' | {'error',atom()} | {'ok',binary() | string()}
diff --git a/lib/dialyzer/test/race_SUITE_data/results/ets_insert_args10 b/lib/dialyzer/test/race_SUITE_data/results/ets_insert_args10
new file mode 100644
index 0000000000..c3c9b12bdd
--- /dev/null
+++ b/lib/dialyzer/test/race_SUITE_data/results/ets_insert_args10
@@ -0,0 +1,2 @@
+
+ets_insert_args10.erl:9: The call ets:insert(T::'foo',[{'counter',number()},...]) might have an unintended effect due to a possible race condition caused by its combination with the ets:lookup(T::'foo','counter') call in ets_insert_args10.erl on line 8
diff --git a/lib/dialyzer/test/race_SUITE_data/src/ets_insert_args10.erl b/lib/dialyzer/test/race_SUITE_data/src/ets_insert_args10.erl
new file mode 100644
index 0000000000..c897a34af0
--- /dev/null
+++ b/lib/dialyzer/test/race_SUITE_data/src/ets_insert_args10.erl
@@ -0,0 +1,19 @@
+%% This tests the presence of possible races due to an ets:lookup/ets:insert
+%% combination. It takes into account the argument types of the calls.
+
+-module(ets_insert_args10).
+-export([start/0]).
+
+start() ->
+ F = fun(T) -> [{_, N}] = ets:lookup(T, counter),
+ ets:insert(T, [{counter, N+1}])
+ end,
+ io:format("Created ~w\n", [ets:new(foo, [named_table, public])]),
+ A = {counter, 0},
+ B = [],
+ ets:insert(foo, [A|B]),
+ io:format("Inserted ~w\n", [{counter, 0}]),
+ F(foo),
+ io:format("Update complete\n", []),
+ ObjectList = ets:lookup(foo, counter),
+ io:format("Counter: ~w\n", [ObjectList]).
diff --git a/lib/dialyzer/test/small_SUITE_data/results/cerl_hipeify b/lib/dialyzer/test/small_SUITE_data/results/cerl_hipeify
index 87bf6f309f..06dc0d63ee 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/cerl_hipeify
+++ b/lib/dialyzer/test/small_SUITE_data/results/cerl_hipeify
@@ -1,4 +1,4 @@
cerl_hipeify.erl:370: Function will never be called
-cerl_hipeify.erl:370: Guard test fun((none()) -> none()) =:= F::{_,_,_} | {_,_,_,_} | {_,_,_,_,_} | {_,_,_,_,_,_} | {_,_,_,_,_,_,_} can never succeed
+cerl_hipeify.erl:370: Guard test fun((none()) -> no_return()) =:= F::{_,_,_} | {_,_,_,_} | {_,_,_,_,_} | {_,_,_,_,_,_} | {_,_,_,_,_,_,_} can never succeed
cerl_hipeify.erl:641: Function env__new_function_name/2 will never be called
diff --git a/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes
new file mode 100644
index 0000000000..4850f3ff0c
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes
@@ -0,0 +1,31 @@
+
+contracts_with_subtypes.erl:106: The call contracts_with_subtypes:rec_arg({'a','b'}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
+contracts_with_subtypes.erl:107: The call contracts_with_subtypes:rec_arg({'b','a'}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
+contracts_with_subtypes.erl:108: The call contracts_with_subtypes:rec_arg({'a',{'b','a'}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
+contracts_with_subtypes.erl:109: The call contracts_with_subtypes:rec_arg({'b',{'a','b'}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
+contracts_with_subtypes.erl:110: The call contracts_with_subtypes:rec_arg({'a',{'b',{'a','b'}}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
+contracts_with_subtypes.erl:111: The call contracts_with_subtypes:rec_arg({'b',{'a',{'b','a'}}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
+contracts_with_subtypes.erl:142: The pattern 1 can never match the type binary() | string()
+contracts_with_subtypes.erl:145: The pattern 'alpha' can never match the type {'ok',_} | {'ok',_,binary() | string()}
+contracts_with_subtypes.erl:147: The pattern 42 can never match the type {'ok',_} | {'ok',_,binary() | string()}
+contracts_with_subtypes.erl:163: The pattern 'alpha' can never match the type {'ok',X}
+contracts_with_subtypes.erl:165: The pattern 42 can never match the type {'ok',X}
+contracts_with_subtypes.erl:183: The pattern 'alpha' can never match the type {'ok',X}
+contracts_with_subtypes.erl:185: The pattern 42 can never match the type {'ok',X}
+contracts_with_subtypes.erl:202: The pattern 1 can never match the type binary() | string()
+contracts_with_subtypes.erl:205: The pattern {'ok', _} can never match the type {'ok',X,binary() | string()}
+contracts_with_subtypes.erl:206: The pattern 'alpha' can never match the type {'ok',X,binary() | string()}
+contracts_with_subtypes.erl:207: The pattern {'ok', 42} can never match the type {'ok',X,binary() | string()}
+contracts_with_subtypes.erl:208: The pattern 42 can never match the type {'ok',X,binary() | string()}
+contracts_with_subtypes.erl:234: Function flat_ets_new_t/0 has no local return
+contracts_with_subtypes.erl:235: The call contracts_with_subtypes:flat_ets_new(12,[]) breaks the contract (Name,Options) -> atom() when is_subtype(Name,atom()), is_subtype(Options,[Option]), is_subtype(Option,'set' | 'ordered_set' | 'bag' | 'duplicate_bag' | 'public' | 'protected' | 'private' | 'named_table' | {'keypos',integer()} | {'heir',pid(),term()} | {'heir','none'} | {'write_concurrency',boolean()} | {'read_concurrency',boolean()} | 'compressed')
+contracts_with_subtypes.erl:23: Invalid type specification for function contracts_with_subtypes:extract2/0. The success typing is () -> 'something'
+contracts_with_subtypes.erl:261: Function factored_ets_new_t/0 has no local return
+contracts_with_subtypes.erl:262: The call contracts_with_subtypes:factored_ets_new(12,[]) breaks the contract (Name,Options) -> atom() when is_subtype(Name,atom()), is_subtype(Options,[Option]), is_subtype(Option,Type | Access | 'named_table' | {'keypos',Pos} | {'heir',Pid::pid(),HeirData} | {'heir','none'} | Tweaks), is_subtype(Type,type()), is_subtype(Access,access()), is_subtype(Tweaks,{'write_concurrency',boolean()} | {'read_concurrency',boolean()} | 'compressed'), is_subtype(Pos,pos_integer()), is_subtype(HeirData,term())
+contracts_with_subtypes.erl:77: The call contracts_with_subtypes:foo1(5) breaks the contract (Arg1) -> Res when is_subtype(Arg1,atom()), is_subtype(Res,atom())
+contracts_with_subtypes.erl:78: The call contracts_with_subtypes:foo2(5) breaks the contract (Arg1) -> Res when is_subtype(Arg1,Arg2), is_subtype(Arg2,atom()), is_subtype(Res,atom())
+contracts_with_subtypes.erl:79: The call contracts_with_subtypes:foo3(5) breaks the contract (Arg1) -> Res when is_subtype(Arg2,atom()), is_subtype(Arg1,Arg2), is_subtype(Res,atom())
+contracts_with_subtypes.erl:7: Invalid type specification for function contracts_with_subtypes:extract/0. The success typing is () -> 'something'
+contracts_with_subtypes.erl:80: The call contracts_with_subtypes:foo4(5) breaks the contract (Type) -> Type when is_subtype(Type,atom())
+contracts_with_subtypes.erl:81: The call contracts_with_subtypes:foo5(5) breaks the contract (Type::atom()) -> Type::atom()
+contracts_with_subtypes.erl:82: The call contracts_with_subtypes:foo6(5) breaks the contract (Type) -> Type when is_subtype(Type,atom())
diff --git a/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy
new file mode 100644
index 0000000000..7ce440a60d
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy
@@ -0,0 +1,4 @@
+
+higher_order_discrepancy.erl:11: The call higher_order_discrepancy:g('foo') will never return since it differs in the 1st argument from the success typing arguments: ('bar')
+higher_order_discrepancy.erl:14: Function g/1 has no local return
+higher_order_discrepancy.erl:14: The pattern 'bar' can never match the type 'foo'
diff --git a/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy_2 b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy_2
new file mode 100644
index 0000000000..c1c7dbbfcc
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy_2
@@ -0,0 +1,8 @@
+
+higher_order_discrepancy_2.erl:11: The call higher_order_discrepancy_2:f('foo') will never return since it differs in the 1st argument from the success typing arguments: ('bar')
+higher_order_discrepancy_2.erl:11: The call higher_order_discrepancy_2:g('foo') will never return since it differs in the 1st argument from the success typing arguments: ('baz')
+higher_order_discrepancy_2.erl:13: Function f/1 has no local return
+higher_order_discrepancy_2.erl:13: The pattern 'bar' can never match the type 'foo'
+higher_order_discrepancy_2.erl:14: Function g/1 has no local return
+higher_order_discrepancy_2.erl:14: The pattern 'baz' can never match the type 'foo'
+higher_order_discrepancy_2.erl:5: Function test/1 has no local return
diff --git a/lib/dialyzer/test/small_SUITE_data/results/inf_loop2 b/lib/dialyzer/test/small_SUITE_data/results/inf_loop2
index 7e9972ad98..142e4b2c37 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/inf_loop2
+++ b/lib/dialyzer/test/small_SUITE_data/results/inf_loop2
@@ -1,4 +1,4 @@
inf_loop2.erl:18: Function test/0 has no local return
inf_loop2.erl:19: The call lists:reverse('gazonk') will never return since it differs in the 1st argument from the success typing arguments: ([any()])
-inf_loop2.erl:22: Function loop/0 has no local return
+inf_loop2.erl:22: Function loop/0 will never be called
diff --git a/lib/dialyzer/test/small_SUITE_data/results/no_local_return b/lib/dialyzer/test/small_SUITE_data/results/no_local_return
new file mode 100644
index 0000000000..6ca1ed51d8
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/no_local_return
@@ -0,0 +1,3 @@
+
+no_local_return.erl:11: Function bar/1 will never be called
+no_local_return.erl:8: Function foo/0 will never be called
diff --git a/lib/dialyzer/test/small_SUITE_data/results/port_info_test b/lib/dialyzer/test/small_SUITE_data/results/port_info_test
index 9ee863f9eb..863a3d61df 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/port_info_test
+++ b/lib/dialyzer/test/small_SUITE_data/results/port_info_test
@@ -3,4 +3,5 @@ port_info_test.erl:10: The pattern {'connected', 42} can never match the type 'u
port_info_test.erl:14: The pattern {'registered_name', "42"} can never match the type 'undefined' | {'registered_name',atom()}
port_info_test.erl:19: The pattern {'output', 42} can never match the type 'undefined' | {'connected',pid()}
port_info_test.erl:24: Guard test 'links' =:= Atom::'connected' can never succeed
-port_info_test.erl:28: The pattern {'gazonk', _} can never match the type 'undefined' | {'connected' | 'id' | 'input' | 'links' | 'name' | 'output' | 'registered_name',atom() | pid() | [pid() | char()] | integer()}
+port_info_test.erl:28: The pattern {'gazonk', _} can never match the type 'undefined' | {'connected' | 'id' | 'input' | 'links' | 'name' | 'os_pid' | 'output' | 'registered_name',atom() | pid() | [pid() | char()] | integer()}
+port_info_test.erl:32: The pattern {'os_pid', "42"} can never match the type 'undefined' | {'os_pid','undefined' | non_neg_integer()}
diff --git a/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash b/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash
index 191d3d4173..8c9df56a4b 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash
+++ b/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash
@@ -12,4 +12,3 @@ tuple_set_crash.erl:179: The pattern <<AudioVolume:16/integer-little-unit:1,Rest
tuple_set_crash.erl:182: The pattern <<Delay:16/integer-little-unit:1,_Padding/binary-unit:8>> can never match the type <<_:8>>
tuple_set_crash.erl:62: The pattern {'play_list', _Playlist} can never match the type 'ok' | {'device_properties',[{atom(),_}]} | {'error',[{atom(),_}]}
tuple_set_crash.erl:64: The pattern {'error', 17} can never match the type 'ok' | {'device_properties',[{atom(),_}]} | {'error',[{atom(),_}]}
-tuple_set_crash.erl:83: The specification for tuple_set_crash:parse_message/1 states that the function might also return {'media_item_url_reply',integer(),binary()} but the inferred return is 'ok' | {'audio_device_info' | 'audio_output_info' | 'audio_target_info' | 'device_properties' | 'error' | 'video_device_info' | 'video_output_info' | 'video_target_info',[{'address' | 'audio_volume' | 'controller_description' | 'controller_name' | 'controller_status' | 'device_id' | 'display_type' | 'fw_version' | 'master_volume' | 'model' | 'output_id' | 'status' | 'target_id',binary() | non_neg_integer()}] | 1..255}
diff --git a/lib/dialyzer/test/small_SUITE_data/src/collapse_lists/a.erl b/lib/dialyzer/test/small_SUITE_data/src/collapse_lists/a.erl
new file mode 100644
index 0000000000..7efe870b0d
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/collapse_lists/a.erl
@@ -0,0 +1,9 @@
+-module(a).
+-export([g/1]).
+
+-export_type([a/0, t/0]).
+-type a() :: integer().
+-type t() :: a() | maybe_improper_list(t(), t()).
+
+-spec g(t()) -> t().
+g(X) -> X.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/collapse_lists/b.erl b/lib/dialyzer/test/small_SUITE_data/src/collapse_lists/b.erl
new file mode 100644
index 0000000000..b08bc5e66c
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/collapse_lists/b.erl
@@ -0,0 +1,5 @@
+-module(b).
+-export([f/1]).
+
+-spec f(a:t()) -> a:t().
+f(X) -> a:g(X).
diff --git a/lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes.erl b/lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes.erl
new file mode 100644
index 0000000000..d72138d509
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes.erl
@@ -0,0 +1,267 @@
+-module(contracts_with_subtypes).
+
+-compile(export_all).
+
+%===============================================================================
+
+-spec extract() -> 'ok'.
+
+extract() ->
+ case dz_extract() of
+ {ok, Val} -> Val;
+ error -> exit(boom)
+ end.
+
+-spec dz_extract() -> RetValue when
+ FileList :: something,
+ RetValue :: {ok, FileList} | error.
+
+dz_extract() -> get(foo).
+
+%-------------------------------------------------------------------------------
+
+-spec extract2() -> 'ok'.
+
+extract2() ->
+ case dz_extract2() of
+ {ok, Val} -> Val;
+ error -> exit(boom)
+ end.
+
+-spec dz_extract2() -> RetValue when
+ RetValue :: {ok, FileList} | error,
+ FileList :: something.
+
+dz_extract2() -> get(foo).
+
+%===============================================================================
+
+-spec foo1(Arg1) -> Res when
+ Arg1 :: atom(),
+ Res :: atom().
+
+foo1(X) -> X.
+
+-spec foo2(Arg1) -> Res when
+ Arg1 :: Arg2,
+ Arg2 :: atom(),
+ Res :: atom().
+
+foo2(X) -> X.
+
+-spec foo3(Arg1) -> Res when
+ Arg2 :: atom(),
+ Arg1 :: Arg2,
+ Res :: atom().
+
+foo3(X) -> X.
+
+-spec foo4(Type) -> Type when is_subtype(Type, atom()).
+
+foo4(X) -> X.
+
+-spec foo5(Type :: atom()) -> Type :: atom().
+
+foo5(X) -> X.
+
+-spec foo6(Type) -> Type when Type :: atom().
+
+foo6(X) -> X.
+
+-spec foo7(Type) -> Type.
+
+foo7(X) -> X.
+
+%-------------------------------------------------------------------------------
+
+bar(1) -> foo1(5);
+bar(2) -> foo2(5);
+bar(3) -> foo3(5);
+bar(4) -> foo4(5);
+bar(5) -> foo5(5);
+bar(6) -> foo6(5);
+bar(7) -> foo7(5).
+
+wrong_foo6() ->
+ b = foo6(a).
+
+%===============================================================================
+
+-spec rec_arg(Arg) -> ok when
+ Arg :: {a, A} | {b, B},
+ A :: a | {b, B},
+ B :: b | {a, A}.
+
+rec_arg(X) -> get(X).
+
+c(aa) -> rec_arg({a, a});
+c(bb) -> rec_arg({b, b});
+c(abb) -> rec_arg({a, {b, b}});
+c(baa) -> rec_arg({b, {a, a}});
+c(abaa) -> rec_arg({a, {b, {a, a}}});
+c(babb) -> rec_arg({b, {a, {b, b}}});
+c(ababb) -> rec_arg({a, {b, {a, {b, b}}}});
+c(babaa) -> rec_arg({b, {a, {b, {a, a}}}}).
+
+w(ab) -> rec_arg({a, b});
+w(ba) -> rec_arg({b, a});
+w(aba) -> rec_arg({a, {b, a}});
+w(bab) -> rec_arg({b, {a, b}});
+w(abab) -> rec_arg({a, {b, {a, b}}});
+w(baba) -> rec_arg({b, {a, {b, a}}});
+w(ababa) -> rec_arg({a, {b, {a, {b, a}}}});
+w(babab) -> rec_arg({b, {a, {b, {a, b}}}}).
+
+%===============================================================================
+
+-type dublo(X) :: {X, X}.
+
+-type weird(X,Y) :: {X, Y, X, X}.
+
+-spec forfun(dublo(Var)) -> ok when Var :: atom().
+
+forfun(_) -> ok.
+
+-spec forfun2(weird(Var, Var)) -> ok when Var :: atom().
+
+forfun2(_) -> ok.
+
+%===============================================================================
+
+-spec shallow(X) -> {ok, X} | {ok, X, file:filename()} | err1 | err2.
+
+shallow(X) -> get(X).
+
+st(X) when is_atom(X) ->
+ case shallow(X) of
+ err1 -> ok;
+ err2 -> ok;
+ {ok, X} -> ok;
+ {ok, X, Res} ->
+ case Res of
+ 1 -> bad;
+ _Other -> ok
+ end;
+ alpha -> bad;
+ {ok, 42} -> bad;
+ 42 -> bad
+ end.
+
+%-------------------------------------------------------------------------------
+
+-spec deep(X) -> Ret when
+ Ret :: {ok, X} | Err,
+ Err :: err1 | err2.
+
+deep(X) -> get(X).
+
+dt(X) when is_atom(X) ->
+ case deep(X) of
+ err1 -> ok;
+ err2 -> ok;
+ {ok, X} -> ok;
+ alpha -> bad;
+ {ok, 42} -> bad;
+ 42 -> bad
+ end.
+
+%-------------------------------------------------------------------------------
+
+-type local_errors() :: err1 | err2.
+
+-spec deep2(X) -> Ret when
+ Ret :: {ok, X} | Err,
+ Err :: local_errors().
+
+deep2(X) -> get(X).
+
+dt2(X) when is_atom(X) ->
+ case deep2(X) of
+ err1 -> ok;
+ err2 -> ok;
+ {ok, X} -> ok;
+ alpha -> bad;
+ {ok, 42} -> bad;
+ 42 -> bad
+ end.
+
+%-------------------------------------------------------------------------------
+
+-spec deep3(X) -> Ret when
+ Ret :: {ok, X, file:filename()} | Err,
+ Err :: local_errors().
+
+deep3(X) -> get(X).
+
+dt3(X) when is_atom(X) ->
+ case deep3(X) of
+ err1 -> ok;
+ err2 -> ok;
+ {ok, X, Res} ->
+ case Res of
+ 1 -> bad;
+ _Other -> ok
+ end;
+ {ok, X} -> bad;
+ alpha -> bad;
+ {ok, 42} -> bad;
+ 42 -> bad
+ end.
+
+%===============================================================================
+
+-spec flat_ets_new(Name, Options) -> atom() when
+ Name :: atom(),
+ Options :: [Option],
+ Option :: set
+ | ordered_set
+ | bag
+ | duplicate_bag
+ | public
+ | protected
+ | private
+ | named_table
+ | {keypos, integer()}
+ | {heir, pid(), term()}
+ | {heir, none}
+ | {write_concurrency, boolean()}
+ | {read_concurrency, boolean()}
+ | compressed.
+
+flat_ets_new(Name, Options) ->
+ get({Name, Options}).
+
+flat_ets_new_t() ->
+ flat_ets_new(12,[]),
+ flat_ets_new({a,b},[]),
+ flat_ets_new(name,[foo]),
+ flat_ets_new(name,{bag}),
+ flat_ets_new(name,bag),
+ ok.
+
+-type access() :: public | protected | private.
+-type type() :: set | ordered_set | bag | duplicate_bag.
+
+-spec factored_ets_new(Name, Options) -> atom() when
+ Name :: atom(),
+ Options :: [Option],
+ Option :: Type | Access | named_table | {keypos,Pos}
+ | {heir, Pid :: pid(), HeirData} | {heir, none} | Tweaks,
+ Type :: type(),
+ Access :: access(),
+ Tweaks :: {write_concurrency, boolean()}
+ | {read_concurrency, boolean()}
+ | compressed,
+ Pos :: pos_integer(),
+ HeirData :: term().
+
+factored_ets_new(Name, Options) ->
+ get({Name, Options}).
+
+factored_ets_new_t() ->
+ factored_ets_new(12,[]),
+ factored_ets_new({a,b},[]),
+ factored_ets_new(name,[foo]),
+ factored_ets_new(name,{bag}),
+ factored_ets_new(name,bag),
+ ok.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/deep_lc.erl b/lib/dialyzer/test/small_SUITE_data/src/deep_lc.erl
new file mode 100644
index 0000000000..d9ca0817d9
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/deep_lc.erl
@@ -0,0 +1,14 @@
+-module(deep_lc).
+
+-export([t/0]).
+
+%% This is compile/test/lc_SUITE:deeply_nested/1
+%%
+%% Used to be _very_ slow. Unknown how slow, but more than 15 hours.
+
+t() ->
+ [[X1,X2,X3,X4,X5,X6,X7(),X8,X9,X10,X11,X12,X13,X14,X15,X16,X17,X18(),X19,X20] ||
+ X1 <- [99],X2 <- [98],X3 <- [97],X4 <- [96],X5 <- [42],X6 <- [17],
+ X7 <- [fun() -> X5*X5 end],X8 <- [12],X9 <- [11],X10 <- [10],
+ X11 <- [9],X12 <- [8],X13 <- [7],X14 <- [6],X15 <- [5],
+ X16 <- [4],X17 <- [3],X18 <- [fun() -> X16+X17 end],X19 <- [2],X20 <- [1]].
diff --git a/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl
new file mode 100644
index 0000000000..ff5ee6bac4
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl
@@ -0,0 +1,14 @@
+-module(higher_order_discrepancy).
+
+-export([test/1]).
+
+test(X) ->
+ F =
+ case X of
+ 1 -> fun f/1;
+ 2 -> fun g/1
+ end,
+ F(foo).
+
+f(foo) -> ok.
+g(bar) -> ok.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy_2.erl b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy_2.erl
new file mode 100644
index 0000000000..4b0d4f6b45
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy_2.erl
@@ -0,0 +1,14 @@
+-module(higher_order_discrepancy_2).
+
+-export([test/1]).
+
+test(X) ->
+ F =
+ case X of
+ 1 -> fun f/1;
+ 2 -> fun g/1
+ end,
+ F(foo).
+
+f(bar) -> ok.
+g(baz) -> ok.
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/dialyzer/test/small_SUITE_data/src/maybe_servers.erl b/lib/dialyzer/test/small_SUITE_data/src/maybe_servers.erl
new file mode 100644
index 0000000000..237f43b1a6
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/maybe_servers.erl
@@ -0,0 +1,31 @@
+-module(maybe_servers).
+
+-export([maybe_server/2, mirror_maybe_server/2]).
+
+maybe_server(O, I) ->
+ case O of
+ no ->
+ maybe_loop(fun(_) -> fin end, I);
+ yes ->
+ maybe_loop(fun(X) -> {ok, X} end, I)
+ end.
+
+maybe_loop(F, X)->
+ case F(X) of
+ {ok, Y} -> maybe_loop(F, Y);
+ fin -> exit(n)
+ end.
+
+mirror_maybe_loop(F, X)->
+ case F(X) of
+ {ok, Y} -> mirror_maybe_loop(F, Y);
+ fin -> exit(n)
+ end.
+
+mirror_maybe_server(O, I) ->
+ case O of
+ no ->
+ mirror_maybe_loop(fun(_) -> fin end, I);
+ yes ->
+ mirror_maybe_loop(fun(X) -> {ok, X} end, I)
+ end.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/no_local_return.erl b/lib/dialyzer/test/small_SUITE_data/src/no_local_return.erl
new file mode 100644
index 0000000000..4e1a0b015a
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/no_local_return.erl
@@ -0,0 +1,12 @@
+-module(no_local_return).
+
+%% NOTE: No function is exported. Dialyzer produced a bogus
+%% 'Function foo/0 has no local return' warning
+%% when in fact typer was finding correct return values for both
+%% these functions.
+
+foo() ->
+ bar(42).
+
+bar(X) ->
+ lists:duplicate(X, gazonk).
diff --git a/lib/dialyzer/test/small_SUITE_data/src/on_load.erl b/lib/dialyzer/test/small_SUITE_data/src/on_load.erl
new file mode 100644
index 0000000000..16533a9caa
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/on_load.erl
@@ -0,0 +1,11 @@
+%%% This is to ensure that "on_load" functions are never reported as unused.
+
+-module(on_load).
+
+-export([foo/0]).
+
+-on_load(bar/0).
+
+foo() -> ok.
+
+bar() -> ok.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/port_info_test.erl b/lib/dialyzer/test/small_SUITE_data/src/port_info_test.erl
index 2ee9a3a6e2..07f22256c9 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/port_info_test.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/port_info_test.erl
@@ -3,7 +3,7 @@
%% and the quality of the warnings that Dialyzer spits out
%%
-module(port_info_test).
--export([t1/1, t2/1, t3/1, t4/1, t5/2, buggy/1]).
+-export([t1/1, t2/1, t3/1, t4/1, t5/2, t6/1, buggy/1]).
%% The following errors are correctly caught, but the messages are a bit weird
t1(X) when is_port(X) ->
@@ -28,6 +28,10 @@ t5(X, Atom) when is_port(X) ->
{gazonk, _} = erlang:port_info(X, Atom);
t5(_, _) -> ok.
+t6(X) when is_port(X) ->
+ {os_pid, "42"} = erlang:port_info(X, os_pid);
+t6(_) -> ok.
+
%% The type system is not strong enough to catch the following errors
buggy(X) when is_atom(X) ->
{links, X} = erlang:port_info(foo, X).
diff --git a/lib/dialyzer/test/small_SUITE_data/src/remote_tuple_set.erl b/lib/dialyzer/test/small_SUITE_data/src/remote_tuple_set.erl
new file mode 100644
index 0000000000..6c440ed04c
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/remote_tuple_set.erl
@@ -0,0 +1,8 @@
+-module(remote_tuple_set).
+
+-export([parse_cidr/0]).
+
+-spec parse_cidr() -> {inet:address_family(),1,2} | {error}.
+
+parse_cidr() ->
+ {inet,1,2}.
diff --git a/lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options b/lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options
new file mode 100644
index 0000000000..f7197ac30f
--- /dev/null
+++ b/lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options
@@ -0,0 +1 @@
+{dialyzer_options, [{warnings, [underspecs]}]}.
diff --git a/lib/dialyzer/test/underspecs_SUITE_data/results/remote b/lib/dialyzer/test/underspecs_SUITE_data/results/remote
new file mode 100644
index 0000000000..1e0cda3bde
--- /dev/null
+++ b/lib/dialyzer/test/underspecs_SUITE_data/results/remote
@@ -0,0 +1,9 @@
+
+remotes1.erl:17: The specification for remotes1:foo5/1 states that the function might also return 'ko' but the inferred return is 'ok'
+remotes1.erl:20: Type specification remotes1:foo6('ok' | 'ko') -> 'ok' is a supertype of the success typing: remotes1:foo6('ok') -> 'ok'
+remotes1.erl:25: The specification for remotes1:foo7/1 states that the function might also return 'ko' but the inferred return is 'ok'
+remotes1.erl:28: Type specification remotes1:foo8(local_type_42()) -> 'ok' is a supertype of the success typing: remotes1:foo8('ok') -> 'ok'
+remotes1.erl:33: The specification for remotes1:foo9/1 states that the function might also return 'ko' but the inferred return is 'ok'
+remotes1.erl:36: Type specification remotes1:foo10(local_and_known_remote_type_42()) -> 'ok' is a supertype of the success typing: remotes1:foo10('ok') -> 'ok'
+remotes1.erl:49: Type specification remotes1:foo13('ok') -> local_and_unknown_remote_type_42() is a supertype of the success typing: remotes1:foo13('ok') -> 'ok'
+remotes1.erl:52: Type specification remotes1:foo14(local_and_unknown_remote_type_42()) -> 'ok' is a supertype of the success typing: remotes1:foo14('ok') -> 'ok'
diff --git a/lib/dialyzer/test/underspecs_SUITE_data/src/remote/remotes1.erl b/lib/dialyzer/test/underspecs_SUITE_data/src/remote/remotes1.erl
new file mode 100644
index 0000000000..b722495095
--- /dev/null
+++ b/lib/dialyzer/test/underspecs_SUITE_data/src/remote/remotes1.erl
@@ -0,0 +1,61 @@
+-module(remotes1).
+
+-compile(export_all).
+
+-spec foo1(some_unknown_remote:type42()) -> ok.
+foo1(ok) -> ok.
+
+-spec foo2(ok) -> some_unknown_remote:type42().
+foo2(ok) -> ok.
+
+-spec foo3(some_known_remote:type42()) -> ok.
+foo3(ok) -> ok.
+
+-spec foo4(ok) -> some_known_remote:type42().
+foo4(ok) -> ok.
+
+-spec foo5(ok|ko) -> ok|ko.
+foo5(ok) -> ok.
+
+-spec foo6(ok|ko) -> ok.
+foo6(ok) -> ok.
+
+-type local_type_42() :: ok | ko.
+
+-spec foo7(ok) -> local_type_42().
+foo7(ok) -> ok.
+
+-spec foo8(local_type_42()) -> ok.
+foo8(ok) -> ok.
+
+-type local_and_known_remote_type_42() :: some_known_remote:type42() | ok | ko.
+
+-spec foo9(ok) -> local_and_known_remote_type_42().
+foo9(ok) -> ok.
+
+-spec foo10(local_and_known_remote_type_42()) -> ok.
+foo10(ok) -> ok.
+
+-type local_and_ok_known_remote_type_42() :: some_known_remote:type42() | ok.
+
+-spec foo11(ok) -> local_and_ok_known_remote_type_42().
+foo11(ok) -> ok.
+
+-spec foo12(local_and_ok_known_remote_type_42()) -> ok.
+foo12(ok) -> ok.
+
+-type local_and_unknown_remote_type_42() :: some_unknown_remote:type42() | ok | ko.
+
+-spec foo13(ok) -> local_and_unknown_remote_type_42().
+foo13(ok) -> ok.
+
+-spec foo14(local_and_unknown_remote_type_42()) -> ok.
+foo14(ok) -> ok.
+
+-type local_and_ok_unknown_remote_type_42() :: some_unknown_remote:type42() | ok.
+
+-spec foo15(ok) -> local_and_ok_unknown_remote_type_42().
+foo15(ok) -> ok.
+
+-spec foo16(local_and_ok_unknown_remote_type_42()) -> ok.
+foo16(ok) -> ok.
diff --git a/lib/dialyzer/test/underspecs_SUITE_data/src/remote/some_known_remote.erl b/lib/dialyzer/test/underspecs_SUITE_data/src/remote/some_known_remote.erl
new file mode 100644
index 0000000000..437f1e7826
--- /dev/null
+++ b/lib/dialyzer/test/underspecs_SUITE_data/src/remote/some_known_remote.erl
@@ -0,0 +1,5 @@
+-module(some_known_remote).
+
+-export_type([type42/0]).
+
+-type type42() :: ok | ko.
diff --git a/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_1 b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_1
new file mode 100644
index 0000000000..de416455e2
--- /dev/null
+++ b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_1
@@ -0,0 +1,2 @@
+
+nowarn_unused_function_1.erl:17: Function f3/1 will never be called
diff --git a/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_2 b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_2
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_2
diff --git a/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_3 b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_3
new file mode 100644
index 0000000000..8ae78673d5
--- /dev/null
+++ b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_3
@@ -0,0 +1,3 @@
+
+nowarn_unused_function_3.erl:12: Function f2/1 will never be called
+nowarn_unused_function_3.erl:9: Function f1/1 will never be called
diff --git a/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_1.erl b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_1.erl
new file mode 100644
index 0000000000..fcce532f73
--- /dev/null
+++ b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_1.erl
@@ -0,0 +1,18 @@
+%% Test that option 'nowarn_unused_funcion' works similarly in
+%% Dialyzer as in the compiler.
+
+-module(nowarn_unused_function_1).
+
+-compile(warn_unused_function).
+
+-compile({nowarn_unused_function,f1/1}).
+f1(_) ->
+ a.
+
+-compile({nowarn_unused_function,[{f2,1}]}).
+f2(_) ->
+ a.
+
+-compile({warn_unused_function,[{f3,1}]}).
+f3(_) ->
+ a.
diff --git a/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_2.erl b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_2.erl
new file mode 100644
index 0000000000..9bc3ab14ea
--- /dev/null
+++ b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_2.erl
@@ -0,0 +1,18 @@
+%% Test that option 'nowarn_unused_funcion' works similarly in
+%% Dialyzer as in the compiler.
+
+-module(nowarn_unused_function_2).
+
+-compile(nowarn_unused_function).
+
+-compile({warn_unused_function,f1/1}).
+f1(_) ->
+ a.
+
+-compile({warn_unused_function,[{f2,1}]}).
+f2(_) ->
+ a.
+
+-compile({nowarn_unused_function,[{f3,1}]}).
+f3(_) ->
+ a.
diff --git a/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_3.erl b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_3.erl
new file mode 100644
index 0000000000..604c5e436b
--- /dev/null
+++ b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_3.erl
@@ -0,0 +1,16 @@
+%% Test that option 'nowarn_unused_funcion' works similarly in
+%% Dialyzer as in the compiler.
+
+-module(nowarn_unused_function_3).
+
+-compile({warn_unused_function,[{f1,1},{f2,1}]}).
+-compile({nowarn_unused_function,[{f3,1}]}).
+
+f1(_) ->
+ a.
+
+f2(_) ->
+ a.
+
+f3(_) ->
+ a.