aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe
diff options
context:
space:
mode:
authorHans Bolinder <[email protected]>2017-09-18 08:29:50 +0200
committerHans Bolinder <[email protected]>2017-09-18 08:29:50 +0200
commit25ad8573ba9e0b225b48f35964afb2eb023ecca4 (patch)
tree975a29cd67b55d2d529ab2c57decb3f762626479 /lib/hipe
parentfe3db9d584a8b52a00323d8173d60d75fd6d0a43 (diff)
parentc4aadfd7f88fa379355d6b5e86833066b859d3b2 (diff)
downloadotp-25ad8573ba9e0b225b48f35964afb2eb023ecca4.tar.gz
otp-25ad8573ba9e0b225b48f35964afb2eb023ecca4.tar.bz2
otp-25ad8573ba9e0b225b48f35964afb2eb023ecca4.zip
Merge branch 'hasse/dialyzer/map_fixes/OTP-14572' into maint
* hasse/dialyzer/map_fixes/OTP-14572: dialyzer: Adjust a test case dialyzer: Modify handling of singleton map key types Dialyzer: Rewrite one map type invariant Dialyzer: Rewrite some of the docs of map types
Diffstat (limited to 'lib/hipe')
-rw-r--r--lib/hipe/cerl/erl_types.erl41
-rw-r--r--lib/hipe/test/opt_verify_SUITE.erl2
-rw-r--r--lib/hipe/test/opt_verify_SUITE_data/call_elim_test_branches_opt_poss.erl10
3 files changed, 33 insertions, 20 deletions
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index f4746fc9d0..abb6c259f6 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -1630,8 +1630,8 @@ lift_list_to_pos_empty(?list(Content, Termination, _)) ->
%% * The keys in Pairs are singleton types.
%% * The values of Pairs must not be unit, and may only be none if the
%% mandatoriness tag is 'optional'.
-%% * Optional must contain no pair {K,V} s.t. K is a subtype of DefaultKey and
-%% V is equal to DefaultKey.
+%% * There is no pair {K, 'optional', V} in Pairs s.t.
+%% K is a subtype of DefaultKey and V is equal to DefaultValue.
%% * DefaultKey must be the empty type iff DefaultValue is the empty type.
%% * DefaultKey must not be a singleton type.
%% * For every key K in Pairs, DefaultKey - K must not be representable; i.e.
@@ -4675,7 +4675,8 @@ from_form({type, _L, map, List}, S, D0, L, C) ->
end
end(List, L, C),
try
- {Pairs, DefK, DefV} = map_from_form(Pairs1, [], [], [], ?none, ?none),
+ Pairs2 = singleton_elements(Pairs1),
+ {Pairs, DefK, DefV} = map_from_form(Pairs2, [], [], [], ?none, ?none),
{t_map(Pairs, DefK, DefV), L5, C5}
catch none -> {t_none(), L5, C5}
end;
@@ -5026,6 +5027,30 @@ list_from_form([H|Tail], S, D, L, C) ->
{T1, L2, C2} = list_from_form(Tail, S, D, L1, C1),
{[H1|T1], L2, C2}.
+%% Separates singleton types in keys (see is_singleton_type/1).
+singleton_elements([]) ->
+ [];
+singleton_elements([{K,?mand,V}=Pair|Pairs]) ->
+ case is_singleton_type(K) of
+ true ->
+ [Pair|singleton_elements(Pairs)];
+ false ->
+ singleton_elements([{K,?opt,V}|Pairs])
+ end;
+singleton_elements([{Key0,MNess,Val}|Pairs]) ->
+ [{Key,MNess,Val} || Key <- separate_key(Key0)] ++ singleton_elements(Pairs).
+
+%% To be in sync with is_singleton_type/1.
+%% Does not separate tuples and maps as doing that has potential
+%% to be very expensive.
+separate_key(?atom(Atoms)) when Atoms =/= ?any ->
+ [t_atom(A) || A <- Atoms];
+separate_key(?number(_, _) = T) ->
+ t_elements(T);
+separate_key(?union(List)) ->
+ lists:append([separate_key(K) || K <- List, not t_is_none(K)]);
+separate_key(Key) -> [Key].
+
%% Sorts, combines non-singleton pairs, and applies precendence and
%% mandatoriness rules.
map_from_form([], ShdwPs, MKs, Pairs, DefK, DefV) ->
@@ -5475,7 +5500,8 @@ t_is_singleton(Type) ->
t_is_singleton(Type, Opaques) ->
do_opaque(Type, Opaques, fun is_singleton_type/1).
-%% Incomplete; not all representable singleton types are included.
+%% To be in sync with separate_key/1.
+%% Used to also recognize maps and tuples.
is_singleton_type(?nil) -> true;
is_singleton_type(?atom(?any)) -> false;
is_singleton_type(?atom(Set)) ->
@@ -5483,13 +5509,6 @@ is_singleton_type(?atom(Set)) ->
is_singleton_type(?int_range(V, V)) -> true;
is_singleton_type(?int_set(Set)) ->
ordsets:size(Set) =:= 1;
-is_singleton_type(?tuple(Types, Arity, _)) when is_integer(Arity) ->
- lists:all(fun is_singleton_type/1, Types);
-is_singleton_type(?tuple_set([{Arity, [OnlyTuple]}])) when is_integer(Arity) ->
- is_singleton_type(OnlyTuple);
-is_singleton_type(?map(Pairs, ?none, ?none)) ->
- lists:all(fun({_,MNess,V}) -> MNess =:= ?mand andalso is_singleton_type(V)
- end, Pairs);
is_singleton_type(_) ->
false.
diff --git a/lib/hipe/test/opt_verify_SUITE.erl b/lib/hipe/test/opt_verify_SUITE.erl
index 86083fa02b..a323c10503 100644
--- a/lib/hipe/test/opt_verify_SUITE.erl
+++ b/lib/hipe/test/opt_verify_SUITE.erl
@@ -44,7 +44,7 @@ call_elim(Config) ->
Icode5 = call_elim_test_file(Config, F3, icode_call_elim),
0 = substring_count(binary:bin_to_list(Icode5), "is_key"),
Icode6 = call_elim_test_file(Config, F3, no_icode_call_elim),
- 3 = substring_count(binary:bin_to_list(Icode6), "is_key"),
+ 2 = substring_count(binary:bin_to_list(Icode6), "is_key"),
ok.
call_elim_test_file(Config, FileName, Option) ->
diff --git a/lib/hipe/test/opt_verify_SUITE_data/call_elim_test_branches_opt_poss.erl b/lib/hipe/test/opt_verify_SUITE_data/call_elim_test_branches_opt_poss.erl
index c8ddfa1e75..12875f41af 100644
--- a/lib/hipe/test/opt_verify_SUITE_data/call_elim_test_branches_opt_poss.erl
+++ b/lib/hipe/test/opt_verify_SUITE_data/call_elim_test_branches_opt_poss.erl
@@ -6,17 +6,11 @@ test(A) ->
if A > 0 ->
true = has_a_field(#{a=>true}),
true = has_a_field(#{b=>1, a=>"2"}),
- true = has_a_field(#{a=>5, c=>4}),
- true = has_tuple_field(#{{ab, 1}=><<"qq">>, 1 =>0}),
- true = has_tuple_field(#{up =>down, {ab, 1}=>[]}),
- true = has_tuple_field(#{{ab, 1}=>42});
+ true = has_a_field(#{a=>5, c=>4});
A =< 0 ->
true = has_a_field(#{a=>q, 'A' =>nej}),
true = has_a_field(#{a=>"hej", false=>true}),
- true = has_a_field(#{a=>3}),
- true = has_tuple_field(#{{ab, 1}=>q, 'A' =>nej}),
- true = has_tuple_field(#{{ab, 1}=>"hej", false=>true}),
- true = has_tuple_field(#{{ab, 1}=>3})
+ true = has_a_field(#{a=>3})
end,
true = has_nil_field(#{[] =>3, b =>"seven"}),
true = has_nil_field(#{"seventeen"=>17, []=>nil}),