From c3f50bc462cc850bdef6b77d1a7a58091a75c936 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Wed, 6 Sep 2017 14:45:23 +0200 Subject: Dialyzer: Rewrite one map type invariant --- lib/hipe/cerl/erl_types.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/hipe/cerl/erl_types.erl') diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index 0883a69918..0b9f0d5c3a 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -1629,8 +1629,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. -- cgit v1.2.3 From 3d05725ceb26611ac8c19cc01df715089dc322d5 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Fri, 1 Sep 2017 11:44:36 +0200 Subject: dialyzer: Modify handling of singleton map key types The test case loop.erl shows that there is a problem with certain singleton key types. Here the internal representation toggles between #{a | b => ...} and #{a => ..., b => ...} The choice is to turn #{a | b => ...} into #{a => ..., b => ...} early (t_from_form()). The aim is to keep as much info as possible (in pairs). However, including complex singleton keys (tuples, maps) in this scheme is potentially too costly, and a bit complicated. So one more choice is made: let atoms and number (and nothing else) be singleton types, and let complex keys go into the default key. --- lib/hipe/cerl/erl_types.erl | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) (limited to 'lib/hipe/cerl/erl_types.erl') diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index 0b9f0d5c3a..2627b08d7e 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -4655,7 +4655,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; @@ -4998,6 +4999,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) -> @@ -5447,7 +5472,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)) -> @@ -5455,13 +5481,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. -- cgit v1.2.3