diff options
author | Hans Bolinder <[email protected]> | 2017-09-18 08:29:50 +0200 |
---|---|---|
committer | Hans Bolinder <[email protected]> | 2017-09-18 08:29:50 +0200 |
commit | 25ad8573ba9e0b225b48f35964afb2eb023ecca4 (patch) | |
tree | 975a29cd67b55d2d529ab2c57decb3f762626479 /lib/hipe | |
parent | fe3db9d584a8b52a00323d8173d60d75fd6d0a43 (diff) | |
parent | c4aadfd7f88fa379355d6b5e86833066b859d3b2 (diff) | |
download | otp-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.erl | 41 | ||||
-rw-r--r-- | lib/hipe/test/opt_verify_SUITE.erl | 2 | ||||
-rw-r--r-- | lib/hipe/test/opt_verify_SUITE_data/call_elim_test_branches_opt_poss.erl | 10 |
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}), |