From 02b31b9229a8631a1ecd9b1de90aa7620f46084b Mon Sep 17 00:00:00 2001
From: Hans Bolinder <hasse@erlang.org>
Date: Tue, 7 Feb 2017 16:56:49 +0100
Subject: dialyzer: Minor fix

---
 lib/dialyzer/src/dialyzer_typesig.erl | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl
index e8d9c06799..4d650592e2 100644
--- a/lib/dialyzer/src/dialyzer_typesig.erl
+++ b/lib/dialyzer/src/dialyzer_typesig.erl
@@ -2088,8 +2088,6 @@ v2_solve_disjunct(Disj, Map, V2State0) ->
 var_occurs_everywhere(V, Masks, NotFailed) ->
   ordsets:is_subset(NotFailed, get_mask(V, Masks)).
 
--dialyzer({no_improper_lists, [v2_solve_disj/10, v2_solve_conj/12]}).
-
 v2_solve_disj([I|Is], [C|Cs], I, Map0, V2State0, UL, MapL, Eval, Uneval,
               Failed0) ->
   Id = C#constraint_list.id,
@@ -2108,10 +2106,10 @@ v2_solve_disj([I|Is], [C|Cs], I, Map0, V2State0, UL, MapL, Eval, Uneval,
   end;
 v2_solve_disj([], [], _I, _Map, V2State, UL, MapL, Eval, Uneval, Failed) ->
   {ok, V2State, lists:reverse(Eval), UL, MapL, lists:reverse(Uneval), Failed};
-v2_solve_disj(every_i, Cs, I, Map, V2State, UL, MapL, Eval, Uneval, Failed) ->
+v2_solve_disj([every_i], Cs, I, Map, V2State, UL, MapL, Eval, Uneval, Failed) ->
   NewIs = case Cs of
             [] -> [];
-            _ -> [I|every_i]
+            _ -> [I, every_i]
           end,
   v2_solve_disj(NewIs, Cs, I, Map, V2State, UL, MapL, Eval, Uneval, Failed);
 v2_solve_disj(Is, [C|Cs], I, Map, V2State, UL, MapL, Eval, Uneval0, Failed) ->
@@ -2207,11 +2205,11 @@ v2_solve_conj([], _Cs, _I, Map, Conj, IsFlat, V2State, UL, NewFs, VarsUp,
       v2_solve_conj(NewFlags, Cs, 1, Map, Conj, IsFlat, V2State,
                     [], [], [U|VarsUp], Map, NewFlags)
   end;
-v2_solve_conj(every_i, Cs, I, Map, Conj, IsFlat, V2State, UL, NewFs, VarsUp,
+v2_solve_conj([every_i], Cs, I, Map, Conj, IsFlat, V2State, UL, NewFs, VarsUp,
               LastMap, LastFlags) ->
   NewIs = case Cs of
             [] -> [];
-            _ -> [I|every_i]
+            _ -> [I, every_i]
           end,
   v2_solve_conj(NewIs, Cs, I, Map, Conj, IsFlat, V2State, UL, NewFs, VarsUp,
                 LastMap, LastFlags);
@@ -2233,8 +2231,8 @@ add_mask_to_flags(Flags, [Im|M], I, L) when I > Im ->
 add_mask_to_flags(Flags, [_|M], _I, L) ->
   {umerge_mask(Flags, M), lists:reverse(L)}.
 
-umerge_mask(every_i, _F) ->
-  every_i;
+umerge_mask([every_i]=Is, _F) ->
+  Is;
 umerge_mask(Is, F) ->
   lists:umerge(Is, F).
 
@@ -2250,7 +2248,7 @@ get_flags(#v2_state{constr_data = ConData}=V2State0, C) ->
     error ->
       ?debug("get_flags Id=~w Flags=all ~w\n", [Id, length(Cs)]),
       V2State = V2State0#v2_state{constr_data = maps:put(Id, {[],[]}, ConData)},
-      {V2State, every_i};
+      {V2State, [every_i]};
     {ok, failed} ->
       {V2State0, failed_list};
     {ok, {Part,U}} when U =/= [] ->
-- 
cgit v1.2.3


From 4827fa95257c1d68bcdcac2c6d4a35cd8b56d8cd Mon Sep 17 00:00:00 2001
From: Hans Bolinder <hasse@erlang.org>
Date: Tue, 28 Feb 2017 13:08:41 +0100
Subject: dialyzer: Fix an opaque bug

An opaque bug that would crash Dialyzer has been fixed.

The bug was reported by Nick Marino.
---
 lib/dialyzer/src/dialyzer_dataflow.erl                 | 18 +++++++++++++-----
 lib/dialyzer/test/opaque_SUITE_data/results/weird      |  3 +++
 .../opaque_SUITE_data/src/weird/weird_warning1.erl     | 18 ++++++++++++++++++
 .../opaque_SUITE_data/src/weird/weird_warning2.erl     | 14 ++++++++++++++
 4 files changed, 48 insertions(+), 5 deletions(-)
 create mode 100644 lib/dialyzer/test/opaque_SUITE_data/results/weird
 create mode 100644 lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning1.erl
 create mode 100644 lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning2.erl

diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index ce292e1140..83ce875280 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -2,7 +2,7 @@
 %%--------------------------------------------------------------------
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
 %%
 %% Licensed under the Apache License, Version 2.0 (the "License");
 %% you may not use this file except in compliance with the License.
@@ -1351,8 +1351,6 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, State, Warns) ->
 	  {Msg, Force} =
 	    case t_is_none(ArgType0) of
 	      true ->
-                PatString = format_patterns(Pats),
-		PatTypes = [PatString, format_type(OrigArgType, State1)],
 		%% See if this is covered by an earlier clause or if it
 		%% simply cannot match
 		OrigArgTypes =
@@ -1360,14 +1358,24 @@ do_clause(C, Arg, ArgType0, OrigArgType, Map, State, Warns) ->
 		    true -> Any = t_any(), [Any || _ <- Pats];
 		    false -> t_to_tlist(OrigArgType)
 		  end,
+                PatString = format_patterns(Pats),
+                ArgTypeString = format_type(OrigArgType, State1),
+                BindResOrig =
+                  bind_pat_vars(Pats, OrigArgTypes, [], Map1, State1),
 		Tag =
-		  case bind_pat_vars(Pats, OrigArgTypes, [], Map1, State1) of
+		  case BindResOrig of
 		    {error,   bind, _, _, _} -> pattern_match;
 		    {error, record, _, _, _} -> record_match;
 		    {error, opaque, _, _, _} -> opaque_match;
 		    {_, _} -> pattern_match_cov
 		  end,
-		{{Tag, PatTypes}, false};
+                PatTypes = case BindResOrig of
+                             {error, opaque, _, _, OpaqueType} ->
+                               [PatString, ArgTypeString,
+                                format_type(OpaqueType, State1)];
+                             _ -> [PatString, ArgTypeString]
+                           end,
+                {{Tag, PatTypes}, false};
 	      false ->
 		%% Try to find out if this is a default clause in a list
 		%% comprehension and supress this. A real Hack(tm)
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/weird b/lib/dialyzer/test/opaque_SUITE_data/results/weird
new file mode 100644
index 0000000000..cffba85b9f
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/weird
@@ -0,0 +1,3 @@
+
+weird_warning1.erl:15: The attempt to match a term of type #b{q::queue:queue(_)} against the pattern {'a', Dict} breaks the opacity of queue:queue(_)
+weird_warning2.erl:13: The attempt to match a term of type <#a{d::dict:dict(_,_)},'my_key','my_value'> against the pattern <{'b', Queue}, Key, Value> breaks the opacity of dict:dict(_,_)
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning1.erl b/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning1.erl
new file mode 100644
index 0000000000..094138e72b
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning1.erl
@@ -0,0 +1,18 @@
+-module(weird_warning1).
+-export([public_func/0]).
+
+-record(a, {
+          d = dict:new() :: dict:dict()
+         }).
+
+-record(b, {
+          q = queue:new() :: queue:queue()
+         }).
+
+public_func() ->
+    add_element(#b{}, my_key, my_value).
+
+add_element(#a{d = Dict}, Key, Value) ->
+    dict:store(Key, Value, Dict);
+add_element(#b{q = Queue}, Key, Value) ->
+    queue:in({Key, Value}, Queue).
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning2.erl b/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning2.erl
new file mode 100644
index 0000000000..4e4512157b
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning2.erl
@@ -0,0 +1,14 @@
+-module(weird_warning2).
+-export([public_func/0]).
+
+-record(a, {d = dict:new() :: dict:dict()}).
+
+-record(b, {q = queue:new() :: queue:queue()}).
+
+public_func() ->
+    add_element(#a{}, my_key, my_value).
+
+add_element(#a{d = Dict}, Key, Value) ->
+    dict:store(Key, Value, Dict);
+add_element(#b{q = Queue}, Key, Value) ->
+    queue:in({Key, Value}, Queue).
-- 
cgit v1.2.3


From 0d12ca4bb9fc85e9db980f1f4f990a7c81c5a7a4 Mon Sep 17 00:00:00 2001
From: Hans Bolinder <hasse@erlang.org>
Date: Tue, 28 Feb 2017 13:26:38 +0100
Subject: dialyzer: Fix a weird warning

---
 lib/dialyzer/test/opaque_SUITE_data/results/weird     |  3 +++
 .../opaque_SUITE_data/src/weird/weird_warning3.erl    | 19 +++++++++++++++++++
 lib/hipe/cerl/erl_types.erl                           | 15 +++++++++++++--
 3 files changed, 35 insertions(+), 2 deletions(-)
 create mode 100644 lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning3.erl

diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/weird b/lib/dialyzer/test/opaque_SUITE_data/results/weird
index cffba85b9f..df69c9b6f2 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/weird
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/weird
@@ -1,3 +1,6 @@
 
 weird_warning1.erl:15: The attempt to match a term of type #b{q::queue:queue(_)} against the pattern {'a', Dict} breaks the opacity of queue:queue(_)
 weird_warning2.erl:13: The attempt to match a term of type <#a{d::dict:dict(_,_)},'my_key','my_value'> against the pattern <{'b', Queue}, Key, Value> breaks the opacity of dict:dict(_,_)
+weird_warning3.erl:14: The call weird_warning3:add_element(#a{d::queue:queue(_)},'my_key','my_value') does not have a term of type #a{d::dict:dict(_,_)} | #b{q::queue:queue(_)} (with opaque subterms) as 1st argument
+weird_warning3.erl:16: The attempt to match a term of type #a{d::queue:queue(_)} against the pattern {'a', Dict} breaks the opacity of queue:queue(_)
+weird_warning3.erl:18: Matching of pattern {'b', Queue} tagged with a record name violates the declared type of #a{d::queue:queue(_)}
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning3.erl b/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning3.erl
new file mode 100644
index 0000000000..b70ca645cb
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/weird/weird_warning3.erl
@@ -0,0 +1,19 @@
+-module(weird_warning3).
+-export([public_func/0]).
+
+-record(a, {
+          d = dict:new() :: dict:dict()
+         }).
+
+-record(b, {
+          q = queue:new() :: queue:queue()
+         }).
+
+public_func() ->
+    %% Notice that t_to_string() will create "#a{d::queue:queue(_)}".
+    add_element({a, queue:new()}, my_key, my_value).
+
+add_element(#a{d = Dict}, Key, Value) ->
+    dict:store(Key, Value, Dict);
+add_element(#b{q = Queue}, Key, Value) ->
+    queue:in({Key, Value}, Queue).
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 10e97ff54d..36652db176 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -543,14 +543,22 @@ t_find_opaque_mismatch(?list(T1, Tl1, _), ?list(T2, Tl2, _), TopType, Opaques) -
   t_find_opaque_mismatch_ordlists([T1, Tl1], [T2, Tl2], TopType, Opaques);
 t_find_opaque_mismatch(T1, ?opaque(_) = T2, TopType, Opaques) ->
   case is_opaque_type(T2, Opaques) of
-    false -> {ok, TopType, T2};
+    false ->
+      case t_is_opaque(T1) andalso compatible_opaque_types(T1, T2) =/= [] of
+        true  -> error;
+        false -> {ok, TopType, T2}
+      end;
     true ->
       t_find_opaque_mismatch(T1, t_opaque_structure(T2), TopType, Opaques)
   end;
 t_find_opaque_mismatch(?opaque(_) = T1, T2, TopType, Opaques) ->
   %% The generated message is somewhat misleading:
   case is_opaque_type(T1, Opaques) of
-    false -> {ok, TopType, T1};
+    false ->
+      case t_is_opaque(T2) andalso compatible_opaque_types(T1, T2) =/= [] of
+        true  -> error;
+        false -> {ok, TopType, T1}
+      end;
     true ->
       t_find_opaque_mismatch(t_opaque_structure(T1), T2, TopType, Opaques)
   end;
@@ -3055,6 +3063,9 @@ inf_opaque_types(IsOpaque1, T1, IsOpaque2, T2, Opaques) ->
       end
   end.
 
+compatible_opaque_types(?opaque(Es1), ?opaque(Es2)) ->
+  [{O1, O2} || O1 <- Es1, O2 <- Es2, is_compat_opaque_names(O1, O2)].
+
 is_compat_opaque_names(Opaque1, Opaque2) ->
   #opaque{mod = Mod1, name = Name1, args = Args1} = Opaque1,
   #opaque{mod = Mod2, name = Name2, args = Args2} = Opaque2,
-- 
cgit v1.2.3


From 79e0af92ffe050a484d0f00d0dd9c4b4f4e9eb02 Mon Sep 17 00:00:00 2001
From: Hans Bolinder <hasse@erlang.org>
Date: Tue, 28 Feb 2017 14:26:15 +0100
Subject: dialyzer: Improve a warning

When a pattern a type do not match, opaque warnings were given
precedence before structure mismatches.

This is no longer always the case.

Mentioned by Nick Marino on erlang-questions.
---
 lib/dialyzer/test/opaque_SUITE_data/results/weird |  4 ++--
 lib/hipe/cerl/erl_types.erl                       | 18 ++++++++++++------
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/weird b/lib/dialyzer/test/opaque_SUITE_data/results/weird
index df69c9b6f2..d7f57cd152 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/weird
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/weird
@@ -1,6 +1,6 @@
 
-weird_warning1.erl:15: The attempt to match a term of type #b{q::queue:queue(_)} against the pattern {'a', Dict} breaks the opacity of queue:queue(_)
-weird_warning2.erl:13: The attempt to match a term of type <#a{d::dict:dict(_,_)},'my_key','my_value'> against the pattern <{'b', Queue}, Key, Value> breaks the opacity of dict:dict(_,_)
+weird_warning1.erl:15: Matching of pattern {'a', Dict} tagged with a record name violates the declared type of #b{q::queue:queue(_)}
+weird_warning2.erl:13: Matching of pattern <{'b', Queue}, Key, Value> tagged with a record name violates the declared type of <#a{d::dict:dict(_,_)},'my_key','my_value'>
 weird_warning3.erl:14: The call weird_warning3:add_element(#a{d::queue:queue(_)},'my_key','my_value') does not have a term of type #a{d::dict:dict(_,_)} | #b{q::queue:queue(_)} (with opaque subterms) as 1st argument
 weird_warning3.erl:16: The attempt to match a term of type #a{d::queue:queue(_)} against the pattern {'a', Dict} breaks the opacity of queue:queue(_)
 weird_warning3.erl:18: Matching of pattern {'b', Queue} tagged with a record name violates the declared type of #a{d::queue:queue(_)}
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 36652db176..a5a3e8c136 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -526,7 +526,8 @@ list_contains_opaque(List, Opaques) ->
   lists:any(fun(E) -> t_contains_opaque(E, Opaques) end, List).
 
 %% t_find_opaque_mismatch/2 of two types should only be used if their
-%% t_inf is t_none() due to some opaque type violation.
+%% t_inf is t_none() due to some opaque type violation. However,
+%% 'error' is returned if a structure mismatch is found.
 %%
 %% The first argument of the function is the pattern and its second
 %% argument the type we are matching against the pattern.
@@ -535,10 +536,10 @@ list_contains_opaque(List, Opaques) ->
                                 'error' | {'ok', erl_type(), erl_type()}.
 
 t_find_opaque_mismatch(T1, T2, Opaques) ->
-  t_find_opaque_mismatch(T1, T2, T2, Opaques).
+  catch t_find_opaque_mismatch(T1, T2, T2, Opaques).
 
 t_find_opaque_mismatch(?any, _Type, _TopType, _Opaques) -> error;
-t_find_opaque_mismatch(?none, _Type, _TopType, _Opaques) -> error;
+t_find_opaque_mismatch(?none, _Type, _TopType, _Opaques) -> throw(error);
 t_find_opaque_mismatch(?list(T1, Tl1, _), ?list(T2, Tl2, _), TopType, Opaques) ->
   t_find_opaque_mismatch_ordlists([T1, Tl1], [T2, Tl2], TopType, Opaques);
 t_find_opaque_mismatch(T1, ?opaque(_) = T2, TopType, Opaques) ->
@@ -574,7 +575,11 @@ t_find_opaque_mismatch(?tuple(_, _, _) = T1, ?tuple_set(_) = T2,
   t_find_opaque_mismatch_lists(Tuples1, Tuples2, TopType, Opaques);
 t_find_opaque_mismatch(T1, ?union(U2), TopType, Opaques) ->
   t_find_opaque_mismatch_lists([T1], U2, TopType, Opaques);
-t_find_opaque_mismatch(_T1, _T2, _TopType, _Opaques) -> error.
+t_find_opaque_mismatch(T1, T2, _TopType, Opaques) ->
+  case t_is_none(t_inf(T1, T2, Opaques)) of
+    false -> error;
+    true  -> throw(error)
+  end.
 
 t_find_opaque_mismatch_ordlists(L1, L2, TopType, Opaques) ->
   List = lists:zipwith(fun(T1, T2) ->
@@ -583,10 +588,11 @@ t_find_opaque_mismatch_ordlists(L1, L2, TopType, Opaques) ->
   t_find_opaque_mismatch_list(List).
 
 t_find_opaque_mismatch_lists(L1, L2, _TopType, Opaques) ->
-  List = [t_find_opaque_mismatch(T1, T2, T2, Opaques) || T1 <- L1, T2 <- L2],
+  List = [catch t_find_opaque_mismatch(T1, T2, T2, Opaques) ||
+           T1 <- L1, T2 <- L2],
   t_find_opaque_mismatch_list(List).
 
-t_find_opaque_mismatch_list([]) -> error;
+t_find_opaque_mismatch_list([]) -> throw(error);
 t_find_opaque_mismatch_list([H|T]) ->
   case H of
     {ok, _T1, _T2} -> H;
-- 
cgit v1.2.3