File 0578-dialyzer-Fix-key-check-of-lists-key-search-member-fi.patch of Package erlang

From f1a00ba58cbfa899d4de2a63b1dbb9a16a9f50ed Mon Sep 17 00:00:00 2001
From: Hans Bolinder <hasse@erlang.org>
Date: Tue, 12 Feb 2019 12:48:31 +0100
Subject: [PATCH 1/2] dialyzer: Fix key check of
 lists:key{search,member,find}()

Replace integers and floats with t_number() since keysearch et al
compare the key (rather than match).

Corrects the commit b3c8e94.
---
 .../test/small_SUITE_data/src/lists_key_bug.erl    | 66 ++++++++++++++++--
 lib/hipe/cerl/erl_bif_types.erl                    |  3 +-
 lib/hipe/cerl/erl_types.erl                        | 79 ++++++++++++----------
 3 files changed, 108 insertions(+), 40 deletions(-)

diff --git a/lib/dialyzer/test/small_SUITE_data/src/lists_key_bug.erl b/lib/dialyzer/test/small_SUITE_data/src/lists_key_bug.erl
index d7cbc27a4d..ad5cf3c503 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/lists_key_bug.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/lists_key_bug.erl
@@ -2,10 +2,11 @@
 
 %% OTP-15570
 
--export([t/1]).
+-export([is_1/1, is_2/1, i/1, t1/0, t2/0, im/0]).
 
-t(V) ->
-    K = key(V),
+%% int_set([3])
+is_1(V) ->
+    K = ikey(V),
     case lists:keyfind(K, 1, [{<<"foo">>, bar}]) of
         false ->
             a;
@@ -13,7 +14,62 @@ t(V) ->
             b
     end.
 
-key(1) ->
+ikey(1) ->
     3;
-key(2) ->
+ikey(2) ->
     <<"foo">>.
+
+%% int_set([3, 5])
+is_2(V) ->
+    K = iskey(V),
+    case lists:keyfind(K, 1, [{<<"foo">>, bar}]) of
+        false ->
+            a;
+        {_, _} ->
+            b
+    end.
+
+iskey(1) ->
+    12;
+iskey(2) ->
+    14;
+iskey(3) ->
+    <<"foo">>.
+
+%% integer()
+i(V) ->
+    K = intkey(V),
+    case lists:keyfind(K, 1, [{9.0, foo}]) of
+        false ->
+            a;
+        {_, _} ->
+            b
+    end.
+
+intkey(K) when is_integer(K) ->
+    K + 9999.
+
+t1() ->
+    case lists:keyfind({17}, 1, [{{17.0}, true}]) of
+        false ->
+            a;
+        {_, _} ->
+            b
+    end.
+
+t2() ->
+    case lists:keyfind({17.0}, 1, [{{17}, true}]) of
+        false ->
+            a;
+        {_, _} ->
+            b
+    end.
+
+%% Note: #{1.0 => a} =/= #{1 => a}.
+im() ->
+    case lists:keyfind(#{1.0 => a}, 1, [{#{1 => a}, foo}]) of
+        false ->
+            a;
+        {_, _} ->
+            b
+    end.
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 799957dfdc..8ae1cd4ab7 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -2224,7 +2224,8 @@ type_order() ->
   [t_number(), t_atom(), t_reference(), t_fun(), t_port(), t_pid(), t_tuple(),
    t_map(), t_list(), t_bitstr()].
 
-key_comparisons_fail(X, KeyPos, TupleList, Opaques) ->
+key_comparisons_fail(X0, KeyPos, TupleList, Opaques) ->
+  X = erl_types:t_widen_to_number(X0),
   lists:all(fun(Tuple) ->
 		Key = type(erlang, element, 2, [KeyPos, Tuple]),
 		t_is_none(t_inf(Key, X, Opaques))
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 9abb4d31d9..c3b9fd48a1 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -66,7 +66,6 @@
 	 t_find_opaque_mismatch/3,
          t_find_unknown_opaque/3,
 	 t_fixnum/0,
-	 t_map/2,
 	 t_non_neg_fixnum/0,
 	 t_pos_fixnum/0,
 	 t_float/0,
@@ -205,6 +204,7 @@
 	 t_unopaque/1, t_unopaque/2,
 	 t_var/1,
 	 t_var_name/1,
+         t_widen_to_number/1,
 	 %% t_assign_variables_to_subtype/2,
 	 type_is_defined/4,
 	 record_field_diffs_to_string/2,
@@ -1594,6 +1594,50 @@ lift_list_to_pos_empty(?nil) -> ?nil;
 lift_list_to_pos_empty(?list(Content, Termination, _)) -> 
   ?list(Content, Termination, ?unknown_qual).
 
+-spec t_widen_to_number(erl_type()) -> erl_type().
+
+%% Widens integers and floats to t_number().
+%% Used by erl_bif_types:key_comparison_fail().
+
+t_widen_to_number(?any) -> ?any;
+t_widen_to_number(?none) -> ?none;
+t_widen_to_number(?unit) -> ?unit;
+t_widen_to_number(?atom(_Set) = T) -> T;
+t_widen_to_number(?bitstr(_Unit, _Base) = T) -> T;
+t_widen_to_number(?float) -> t_number();
+t_widen_to_number(?function(Domain, Range)) ->
+  ?function(t_widen_to_number(Domain), t_widen_to_number(Range));
+t_widen_to_number(?identifier(_Types) = T) -> T;
+t_widen_to_number(?int_range(_From, _To)) -> t_number();
+t_widen_to_number(?int_set(_Set)) -> t_number();
+t_widen_to_number(?integer(_Types)) -> t_number();
+t_widen_to_number(?list(Type, Tail, Size)) ->
+  ?list(t_widen_to_number(Type), t_widen_to_number(Tail), Size);
+t_widen_to_number(?map(Pairs, DefK, DefV)) ->
+  L = [{t_widen_to_number(K), MNess, t_widen_to_number(V)} ||
+        {K, MNess, V} <- Pairs],
+  t_map(L, t_widen_to_number(DefK), t_widen_to_number(DefV));
+t_widen_to_number(?matchstate(_P, _Slots) = T) -> T;
+t_widen_to_number(?nil) -> ?nil;
+t_widen_to_number(?number(_Set, _Tag)) -> t_number();
+t_widen_to_number(?opaque(Set)) ->
+  L = [Opaque#opaque{struct = t_widen_to_number(S)} ||
+        #opaque{struct = S} = Opaque <- set_to_list(Set)],
+  ?opaque(ordsets:from_list(L));
+t_widen_to_number(?product(Types)) ->
+  ?product(list_widen_to_number(Types));
+t_widen_to_number(?tuple(?any, _, _) = T) -> T;
+t_widen_to_number(?tuple(Types, Arity, Tag)) ->
+  ?tuple(list_widen_to_number(Types), Arity, Tag);
+t_widen_to_number(?tuple_set(_) = Tuples) ->
+  t_sup([t_widen_to_number(T) || T <- t_tuple_subtypes(Tuples)]);
+t_widen_to_number(?union(List)) ->
+  ?union(list_widen_to_number(List));
+t_widen_to_number(?var(_Id)= T) -> T.
+
+list_widen_to_number(List) ->
+  [t_widen_to_number(E) || E <- List].
+
 %%-----------------------------------------------------------------------------
 %% Maps
 %%
@@ -4156,39 +4200,6 @@ t_abstract_records(?opaque(_)=Type, RecDict) ->
 t_abstract_records(T, _RecDict) -> 
   T.
 
-%% Map over types. Depth first. Used by the contract checker. ?list is
-%% not fully implemented so take care when changing the type in Termination.
-
--spec t_map(fun((erl_type()) -> erl_type()), erl_type()) -> erl_type().
-
-t_map(Fun, ?list(Contents, Termination, Size)) ->
-  Fun(?list(t_map(Fun, Contents), t_map(Fun, Termination), Size));
-t_map(Fun, ?function(Domain, Range)) ->
-  Fun(?function(t_map(Fun, Domain), t_map(Fun, Range)));
-t_map(Fun, ?product(Types)) -> 
-  Fun(?product([t_map(Fun, T) || T <- Types]));
-t_map(Fun, ?union(Types)) ->
-  Fun(t_sup([t_map(Fun, T) || T <- Types]));
-t_map(Fun, ?tuple(?any, ?any, ?any) = T) ->
-  Fun(T);
-t_map(Fun, ?tuple(Elements, _Arity, _Tag)) ->
-  Fun(t_tuple([t_map(Fun, E) || E <- Elements]));
-t_map(Fun, ?tuple_set(_) = Tuples) ->
-  Fun(t_sup([t_map(Fun, T) || T <- t_tuple_subtypes(Tuples)]));
-t_map(Fun, ?opaque(Set)) ->
-  L = [Opaque#opaque{struct = NewS} ||
-        #opaque{struct = S} = Opaque <- set_to_list(Set),
-        not t_is_none(NewS = t_map(Fun, S))],
-  Fun(case L of
-        [] -> ?none;
-        _ -> ?opaque(ordsets:from_list(L))
-      end);
-t_map(Fun, ?map(Pairs,DefK,DefV)) ->
-  %% TODO:
-  Fun(t_map(Pairs, Fun(DefK), Fun(DefV)));
-t_map(Fun, T) ->
-  Fun(T).
-
 %%=============================================================================
 %%
 %% Prettyprinter
-- 
2.16.4