From 985f5a1fae38caed84cde8bc09f6f60e91710f20 Mon Sep 17 00:00:00 2001
From: Hans Bolinder <hasse@erlang.org>
Date: Wed, 15 Nov 2017 12:57:57 +0100
Subject: dialyzer: Extend the map implementation's handling of ?unit

The Maps implementation handles ?unit in more cases.

Exactly when t_is_none_or_unit() is to be called is not clear to me.
The added cases are about a map type being ?unit, but the key or the
value of an association can also be ?unit, but that is not always
checked.
---
 lib/dialyzer/src/dialyzer_typesig.erl                 | 12 +++++++-----
 lib/dialyzer/test/map_SUITE_data/results/map_anon_fun |  2 ++
 lib/dialyzer/test/map_SUITE_data/src/map_anon_fun.erl |  9 +++++++++
 3 files changed, 18 insertions(+), 5 deletions(-)
 create mode 100644 lib/dialyzer/test/map_SUITE_data/results/map_anon_fun
 create mode 100644 lib/dialyzer/test/map_SUITE_data/src/map_anon_fun.erl

(limited to 'lib/dialyzer')

diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl
index c4d8f45447..d03326ec97 100644
--- a/lib/dialyzer/src/dialyzer_typesig.erl
+++ b/lib/dialyzer/src/dialyzer_typesig.erl
@@ -41,7 +41,7 @@
 	 t_is_float/1, t_is_fun/1,
 	 t_is_integer/1, t_non_neg_integer/0,
 	 t_is_list/1, t_is_nil/1, t_is_none/1, t_is_number/1,
-	 t_is_singleton/1,
+	 t_is_singleton/1, t_is_none_or_unit/1,
 
          t_limit/2, t_list/0, t_list/1,
 	 t_list_elements/1, t_nonempty_list/1, t_maybe_improper_list/0,
@@ -528,13 +528,14 @@ traverse(Tree, DefinedVars, State) ->
 		    false -> t_any();
 		    true ->
 		      MT = t_inf(lookup_type(MapVar, Map), t_map()),
-		      case t_is_none(MT) of
+		      case t_is_none_or_unit(MT) of
 			true -> t_none();
 			false ->
 			  DisjointFromKeyType =
 			    fun(ShadowKey) ->
-				t_is_none(t_inf(lookup_type(ShadowKey, Map),
-						KeyType))
+                                ST = t_inf(lookup_type(ShadowKey, Map),
+                                           KeyType),
+				t_is_none_or_unit(ST)
 			    end,
 			  case lists:all(DisjointFromKeyType, ShadowKeys) of
 			    true -> t_map_get(KeyType, MT);
@@ -567,7 +568,8 @@ traverse(Tree, DefinedVars, State) ->
 			  case cerl:is_literal(OpTree) andalso
 			    cerl:concrete(OpTree) =:= exact of
 			    true ->
-			      case t_is_none(t_inf(ShadowedKeys, KeyType)) of
+                              ST = t_inf(ShadowedKeys, KeyType),
+                              case t_is_none_or_unit(ST) of
 				true ->
 				  t_map_put({KeyType, t_any()}, AccType);
 				false ->
diff --git a/lib/dialyzer/test/map_SUITE_data/results/map_anon_fun b/lib/dialyzer/test/map_SUITE_data/results/map_anon_fun
new file mode 100644
index 0000000000..cfca5b1407
--- /dev/null
+++ b/lib/dialyzer/test/map_SUITE_data/results/map_anon_fun
@@ -0,0 +1,2 @@
+
+map_anon_fun.erl:4: Function g/1 will never be called
diff --git a/lib/dialyzer/test/map_SUITE_data/src/map_anon_fun.erl b/lib/dialyzer/test/map_SUITE_data/src/map_anon_fun.erl
new file mode 100644
index 0000000000..e77016d68a
--- /dev/null
+++ b/lib/dialyzer/test/map_SUITE_data/src/map_anon_fun.erl
@@ -0,0 +1,9 @@
+-module(map_anon_fun).
+
+%% Not exported.
+g(A) ->
+    maps:map(fun F(K, {V, _C}) ->
+                    F(K, V);
+                 F(_K, _V) ->
+                    #{ system => {A} }
+            end, #{}).
-- 
cgit v1.2.3