aboutsummaryrefslogtreecommitdiffstats
path: root/lib/dialyzer
diff options
context:
space:
mode:
authorHans Bolinder <[email protected]>2018-02-15 16:30:12 +0100
committerHans Bolinder <[email protected]>2018-02-21 10:10:24 +0100
commit40a3cb7a4657175e5f385d326a63ef012f51585d (patch)
treec18d442eef54736fc59d1e9e6fc136731300ba38 /lib/dialyzer
parente55df241937d62ec15fedac4a9aa4c4c34fddee5 (diff)
downloadotp-40a3cb7a4657175e5f385d326a63ef012f51585d.tar.gz
otp-40a3cb7a4657175e5f385d326a63ef012f51585d.tar.bz2
otp-40a3cb7a4657175e5f385d326a63ef012f51585d.zip
dialyzer: Correct a parameterized opaque types bug
See also https://bugs.erlang.org/browse/ERL-565. To avoid loops, erl_types:t_is_subtype checks for equality using unopaqued types, but in (at least) one case something is lost: This fix makes sure that when forwarding arguments in dataflow, types with different parameters but equal when unopaqued are considered different. For example, dict:dict(0, {}) and dict:dict(0, []) are equal when unopaqued (due to how dict(_, _) is declared in module dict), but should be considered different when forwarding args.
Diffstat (limited to 'lib/dialyzer')
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl14
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/para_bug/same.erl15
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/para_bug/same_type.erl13
3 files changed, 35 insertions, 7 deletions
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index fca5b74a9e..ea3523a965 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -3443,19 +3443,19 @@ state__fun_info(Fun, #state{callgraph = CG, fun_tab = FunTab, plt = PLT}) ->
{Fun, Sig, Contract, LocalRet}.
forward_args(Fun, ArgTypes, #state{work = Work, fun_tab = FunTab} = State) ->
- {OldArgTypes, OldOut, Fixpoint} =
+ {NewArgTypes, OldOut, Fixpoint} =
case dict:find(Fun, FunTab) of
- {ok, {not_handled, {OldArgTypes0, OldOut0}}} ->
- {OldArgTypes0, OldOut0, false};
+ {ok, {not_handled, {_OldArgTypesAreNone, OldOut0}}} ->
+ {ArgTypes, OldOut0, false};
{ok, {OldArgTypes0, OldOut0}} ->
- {OldArgTypes0, OldOut0,
- t_is_subtype(t_product(ArgTypes), t_product(OldArgTypes0))}
+ NewArgTypes0 = [t_sup(X, Y) ||
+ {X, Y} <- lists:zip(ArgTypes, OldArgTypes0)],
+ {NewArgTypes0, OldOut0,
+ t_is_equal(t_product(NewArgTypes0), t_product(OldArgTypes0))}
end,
case Fixpoint of
true -> State;
false ->
- NewArgTypes = [t_sup(X, Y) ||
- {X, Y} <- lists:zip(ArgTypes, OldArgTypes)],
NewWork = add_work(Fun, Work),
?debug("~tw: forwarding args ~ts\n",
[state__lookup_name(Fun, State),
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/para_bug/same.erl b/lib/dialyzer/test/opaque_SUITE_data/src/para_bug/same.erl
new file mode 100644
index 0000000000..44149f4199
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/para_bug/same.erl
@@ -0,0 +1,15 @@
+-module(same).
+
+-export([baz/1]).
+
+-record(bar, {
+ a :: same_type:st(integer()),
+ b :: same_type:st(atom())
+ }).
+
+baz(Bar) ->
+ _ = wrap_find(0, Bar#bar.a),
+ wrap_find(0, Bar#bar.b).
+
+wrap_find(K, D) ->
+ same_type:t(K, D).
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/para_bug/same_type.erl b/lib/dialyzer/test/opaque_SUITE_data/src/para_bug/same_type.erl
new file mode 100644
index 0000000000..855a5d30be
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/para_bug/same_type.erl
@@ -0,0 +1,13 @@
+-module(same_type).
+
+-export([t/2]).
+
+-export_type([st/1]).
+
+%% When unopaqued all specializations of st/1 are equal.
+-opaque st(_A) :: {st, tuple()}.
+
+-spec t(_, st(_)) -> _.
+
+t(K, V) ->
+ {K, V}.