summaryrefslogtreecommitdiff
path: root/lib/dialyzer/src/erl_types.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dialyzer/src/erl_types.erl')
-rw-r--r--lib/dialyzer/src/erl_types.erl725
1 files changed, 231 insertions, 494 deletions
diff --git a/lib/dialyzer/src/erl_types.erl b/lib/dialyzer/src/erl_types.erl
index ed0264cc2f..8068baf8e8 100644
--- a/lib/dialyzer/src/erl_types.erl
+++ b/lib/dialyzer/src/erl_types.erl
@@ -77,7 +77,6 @@
t_from_form_check_remote/4,
t_check_record_fields/6,
t_from_range/2,
- t_from_range_unsafe/2,
t_from_term/1,
t_fun/0,
t_fun/1,
@@ -106,13 +105,11 @@
t_is_any_atom/2, t_is_any_atom/3,
t_is_binary/1, t_is_binary/2,
t_is_bitstr/1, t_is_bitstr/2,
- t_is_bitwidth/1,
t_is_boolean/1, t_is_boolean/2,
t_is_byte/1,
t_is_char/1,
t_is_cons/1, t_is_cons/2,
t_is_equal/2,
- t_is_fixnum/1,
t_is_float/1, t_is_float/2,
t_is_fun/1, t_is_fun/2,
t_is_identifier/1,
@@ -122,7 +119,6 @@
t_is_list/1,
t_is_map/1,
t_is_map/2,
- t_is_matchstate/1,
t_is_nil/1, t_is_nil/2,
t_is_non_neg_integer/1,
t_is_none/1,
@@ -157,13 +153,6 @@
t_map_pairwise_merge/4,
t_map_put/2, t_map_put/3,
t_map_remove/3,
- t_matchstate/0,
- t_matchstate/2,
- t_matchstate_present/1,
- t_matchstate_slot/2,
- t_matchstate_slots/1,
- t_matchstate_update_present/2,
- t_matchstate_update_slot/3,
t_mfa/0,
t_module/0,
t_nil/0,
@@ -185,7 +174,6 @@
%% t_maybe_improper_list/2,
t_product/1,
t_reference/0,
- t_singleton_to_term/2,
t_string/0,
t_subst/2,
t_subtract/2,
@@ -258,9 +246,6 @@
-define(UNIT_MULTIPLIER, 8).
--define(TAG_IMMED1_SIZE, 4).
--define(BITS, (erlang:system_info(wordsize) * 8) - ?TAG_IMMED1_SIZE).
-
-define(MAX_TUPLE_SIZE, (1 bsl 10)).
%%-----------------------------------------------------------------------------
@@ -273,7 +258,6 @@
-define(identifier_tag, identifier).
-define(list_tag, list).
-define(map_tag, map).
--define(matchstate_tag, matchstate).
-define(nil_tag, nil).
-define(number_tag, number).
-define(opaque_tag, opaque).
@@ -284,7 +268,7 @@
-define(var_tag, var).
-type tag() :: ?atom_tag | ?binary_tag | ?function_tag | ?identifier_tag
- | ?list_tag | ?map_tag | ?matchstate_tag | ?nil_tag | ?number_tag
+ | ?list_tag | ?map_tag | ?nil_tag | ?number_tag
| ?opaque_tag | ?product_tag
| ?tuple_tag | ?tuple_set_tag | ?union_tag | ?var_tag.
@@ -327,15 +311,15 @@
arity = 0 :: arity(), struct :: erl_type()}).
-define(atom(Set), #c{tag=?atom_tag, elements=Set}).
--define(bitstr(Unit, Base), #c{tag=?binary_tag, elements=[Unit,Base]}).
+-define(bitstr(Unit, Base), #c{tag=?binary_tag, elements={Unit,Base}}).
-define(float, ?number(?any, ?float_qual)).
-define(function(Domain, Range), #c{tag=?function_tag,
- elements=[Domain, Range]}).
+ elements={Domain,Range}}).
-define(identifier(Types), #c{tag=?identifier_tag, elements=Types}).
-define(integer(Types), ?number(Types, ?integer_qual)).
-define(int_range(From, To), ?integer(#int_rng{from=From, to=To})).
-define(int_set(Set), ?integer(#int_set{set=Set})).
--define(list(Types, Term, Size), #c{tag=?list_tag, elements=[Types,Term],
+-define(list(Types, Term, Size), #c{tag=?list_tag, elements={Types,Term},
qualifier=Size}).
-define(nil, #c{tag=?nil_tag}).
-define(nonempty_list(Types, Term),?list(Types, Term, ?nonempty_qual)).
@@ -350,9 +334,6 @@
-define(tuple_set(Tuples), #c{tag=?tuple_set_tag, elements=Tuples}).
-define(var(Id), #c{tag=?var_tag, elements=Id}).
--define(matchstate(P, Slots), #c{tag=?matchstate_tag, elements=[P,Slots]}).
--define(any_matchstate, ?matchstate(t_bitstr(), ?any)).
-
-define(byte, ?int_range(0, ?MAX_BYTE)).
-define(char, ?int_range(0, ?MAX_CHAR)).
-define(integer_pos, ?int_range(1, pos_inf)).
@@ -363,7 +344,7 @@
-type file_line() :: {file:name(), erl_anno:line()}.
-type record_key() :: {'record', atom()}.
--type type_key() :: {'type' | 'opaque', {atom(), arity()}}.
+-type type_key() :: {'type' | 'opaque', atom(), arity()}.
-type field() :: {atom(), erl_parse:abstract_expr(), erl_type()}.
-type record_value() :: {file_line(),
[{RecordSize :: non_neg_integer(), [field()]}]}.
@@ -380,18 +361,21 @@
%% Unions
%%
--define(union(List), #c{tag=?union_tag, elements=[_,_,_,_,_,_,_,_,_,_]=List}).
-
--define(atom_union(T), ?union([T,?none,?none,?none,?none,?none,?none,?none,?none,?none])).
--define(bitstr_union(T), ?union([?none,T,?none,?none,?none,?none,?none,?none,?none,?none])).
--define(function_union(T), ?union([?none,?none,T,?none,?none,?none,?none,?none,?none,?none])).
--define(identifier_union(T), ?union([?none,?none,?none,T,?none,?none,?none,?none,?none,?none])).
--define(list_union(T), ?union([?none,?none,?none,?none,T,?none,?none,?none,?none,?none])).
--define(number_union(T), ?union([?none,?none,?none,?none,?none,T,?none,?none,?none,?none])).
--define(tuple_union(T), ?union([?none,?none,?none,?none,?none,?none,T,?none,?none,?none])).
--define(matchstate_union(T), ?union([?none,?none,?none,?none,?none,?none,?none,T,?none,?none])).
--define(opaque_union(T), ?union([?none,?none,?none,?none,?none,?none,?none,?none,T,?none])).
--define(map_union(T), ?union([?none,?none,?none,?none,?none,?none,?none,?none,?none,T])).
+-define(union(List), #c{tag=?union_tag, elements=List}).
+-define(untagged_union(A, B, F, I, L, N, T, O, Map), [A,B,F,I,L,N,T,O,Map]).
+
+-define(num_types_in_union, length(?untagged_union(?any, ?any, ?any, ?any, ?any,
+ ?any, ?any, ?any, ?any))).
+
+-define(atom_union(T), ?union([T,?none,?none,?none,?none,?none,?none,?none,?none])).
+-define(bitstr_union(T), ?union([?none,T,?none,?none,?none,?none,?none,?none,?none])).
+-define(function_union(T), ?union([?none,?none,T,?none,?none,?none,?none,?none,?none])).
+-define(identifier_union(T), ?union([?none,?none,?none,T,?none,?none,?none,?none,?none])).
+-define(list_union(T), ?union([?none,?none,?none,?none,T,?none,?none,?none,?none])).
+-define(number_union(T), ?union([?none,?none,?none,?none,?none,T,?none,?none,?none])).
+-define(tuple_union(T), ?union([?none,?none,?none,?none,?none,?none,T,?none,?none])).
+-define(opaque_union(T), ?union([?none,?none,?none,?none,?none,?none,?none,T,?none])).
+-define(map_union(T), ?union([?none,?none,?none,?none,?none,?none,?none,?none,T])).
-define(integer_union(T), ?number_union(T)).
-define(float_union(T), ?number_union(T)).
-define(nil_union(T), ?list_union(T)).
@@ -464,7 +448,7 @@ has_opaque_subtype(T) ->
-spec t_opaque_structure(erl_type()) -> erl_type().
t_opaque_structure(?opaque(Elements)) ->
- t_sup([Struct || #opaque{struct = Struct} <- ordsets:to_list(Elements)]).
+ t_sup([Struct || #opaque{struct = Struct} <- Elements]).
-spec t_contains_opaque(erl_type()) -> boolean().
@@ -489,11 +473,12 @@ t_contains_opaque(?identifier(_Types), _Opaques) -> false;
t_contains_opaque(?int_range(_From, _To), _Opaques) -> false;
t_contains_opaque(?int_set(_Set), _Opaques) -> false;
t_contains_opaque(?integer(_Types), _Opaques) -> false;
+t_contains_opaque(?list(Type, ?nil, _), Opaques) ->
+ t_contains_opaque(Type, Opaques);
t_contains_opaque(?list(Type, Tail, _), Opaques) ->
t_contains_opaque(Type, Opaques) orelse t_contains_opaque(Tail, Opaques);
t_contains_opaque(?map(_, _, _) = Map, Opaques) ->
list_contains_opaque(map_all_types(Map), Opaques);
-t_contains_opaque(?matchstate(_P, _Slots), _Opaques) -> false;
t_contains_opaque(?nil, _Opaques) -> false;
t_contains_opaque(?number(_Set, _Tag), _Opaques) -> false;
t_contains_opaque(?opaque(_)=T, Opaques) ->
@@ -512,8 +497,9 @@ t_contains_opaque(?var(_Id), _Opaques) -> false.
-spec list_contains_opaque([erl_type()], [erl_type()]) -> boolean().
-list_contains_opaque(List, Opaques) ->
- lists:any(fun(E) -> t_contains_opaque(E, Opaques) end, List).
+list_contains_opaque([H|T], Opaques) ->
+ t_contains_opaque(H, Opaques) orelse list_contains_opaque(T, Opaques);
+list_contains_opaque([], _Opaques) -> false.
%% t_find_opaque_mismatch/2 of two types should only be used if their
%% t_inf is t_none() due to some opaque type violation. However,
@@ -667,7 +653,7 @@ decorate(Type, _T, _Opaques) -> Type.
%% Note: it is important that #opaque.struct is a subtype of the
%% opaque type.
decorate_with_opaque(Type, ?opaque(Set2), Opaques) ->
- case decoration(set_to_list(Set2), Type, Opaques, [], false) of
+ case decoration(Set2, Type, Opaques, [], false) of
{[], false} -> Type;
{List, All} when List =/= [] ->
NewType = sup_opaque(List),
@@ -700,9 +686,9 @@ list_decorate(List, L, Opaques) ->
union_decorate(U1, U2, Opaques) ->
Union = union_decorate(U1, U2, Opaques, 0, []),
- [A,B,F,I,L,N,T,M,_,Map] = U1,
- [_,_,_,_,_,_,_,_,Opaque,_] = U2,
- List = [A,B,F,I,L,N,T,M,Map],
+ ?untagged_union(A,B,F,I,L,N,T,_,Map) = U1,
+ ?untagged_union(_,_,_,_,_,_,_,Opaque,_) = U2,
+ List = [A,B,F,I,L,N,T,Map],
DecList = [Dec ||
E <- List,
not t_is_none(E),
@@ -761,25 +747,12 @@ decorate_tuples_in_sets([], _L, _Opaques, Acc) ->
-spec t_opaque_from_records(type_table()) -> [erl_type()].
t_opaque_from_records(RecMap) ->
- OpaqueRecMap =
- maps:filter(fun(Key, _Value) ->
- case Key of
- {opaque, _Name, _Arity} -> true;
- _ -> false
- end
- end, RecMap),
- OpaqueTypeMap =
- maps:map(fun({opaque, Name, _Arity},
- {{Module, _FileLocation, _Form, ArgNames}, _Type}) ->
- %% Args = args_to_types(ArgNames),
- %% List = lists:zip(ArgNames, Args),
- %% TmpVarTab = maps:to_list(List),
- %% Rep = t_from_form(Type, RecDict, TmpVarTab),
- Rep = t_any(), % not used for anything right now
- Args = [t_any() || _ <- ArgNames],
- t_opaque(Module, Name, Args, Rep)
- end, OpaqueRecMap),
- [OpaqueType || {_Key, OpaqueType} <- maps:to_list(OpaqueTypeMap)].
+ Any = t_any(),
+ [begin
+ Rep = Any, % not used for anything right now
+ Args = [Any || _ <- ArgNames],
+ t_opaque(Module, Name, Args, Rep)
+ end || {opaque, Name, _} := {{Module, _, _, ArgNames}, _} <- RecMap].
%%-----------------------------------------------------------------------------
%% Unit type. Signals non termination.
@@ -835,7 +808,7 @@ t_atom_vals(Type, Opaques) ->
do_opaque(Type, Opaques, fun atom_vals/1).
atom_vals(?atom(?any)) -> unknown;
-atom_vals(?atom(Set)) -> set_to_list(Set);
+atom_vals(?atom(Set)) -> Set;
atom_vals(?opaque(_)) -> unknown;
atom_vals(Other) ->
?atom(_) = Atm = t_inf(t_atom(), Other),
@@ -887,15 +860,15 @@ t_is_boolean(Type, Opaques) ->
t_boolean() ->
?atom(set_from_list([false, true])).
-is_boolean(?atom(?any)) -> false;
is_boolean(?atom(Set)) ->
- case set_size(Set) of
- 1 -> set_is_element(true, Set) orelse set_is_element(false, Set);
- 2 -> set_is_element(true, Set) andalso set_is_element(false, Set);
- N when is_integer(N), N > 2 -> false
+ case Set of
+ [Atom] when erlang:is_boolean(Atom) -> true;
+ [false,true] -> true;
+ _ -> false
end;
is_boolean(_) -> false.
+
%%-----------------------------------------------------------------------------
%% Binaries
%%
@@ -997,92 +970,6 @@ is_bitstr(?bitstr(_, _)) -> true;
is_bitstr(_) -> false.
%%-----------------------------------------------------------------------------
-%% Matchstates
-%%
-
--spec t_matchstate() -> erl_type().
-
-t_matchstate() ->
- ?any_matchstate.
-
--spec t_matchstate(erl_type(), non_neg_integer()) -> erl_type().
-
-t_matchstate(Init, 0) ->
- ?matchstate(Init, Init);
-t_matchstate(Init, Max) when is_integer(Max) ->
- Slots = [Init|[?none || _ <- lists:seq(1, Max)]],
- ?matchstate(Init, t_product(Slots)).
-
--spec t_is_matchstate(erl_type()) -> boolean().
-
-t_is_matchstate(?matchstate(_, _)) -> true;
-t_is_matchstate(_) -> false.
-
--spec t_matchstate_present(erl_type()) -> erl_type().
-
-t_matchstate_present(Type) ->
- case t_inf(t_matchstate(), Type) of
- ?matchstate(P, _) -> P;
- _ -> ?none
- end.
-
--spec t_matchstate_slot(erl_type(), non_neg_integer()) -> erl_type().
-
-t_matchstate_slot(Type, Slot) ->
- RealSlot = Slot + 1,
- case t_inf(t_matchstate(), Type) of
- ?matchstate(_, ?any) -> ?any;
- ?matchstate(_, ?product(Vals)) when length(Vals) >= RealSlot ->
- lists:nth(RealSlot, Vals);
- ?matchstate(_, ?product(_)) ->
- ?none;
- ?matchstate(_, SlotType) when RealSlot =:= 1 ->
- SlotType;
- _ ->
- ?none
- end.
-
--spec t_matchstate_slots(erl_type()) -> erl_type().
-
-t_matchstate_slots(?matchstate(_, Slots)) ->
- Slots.
-
--spec t_matchstate_update_present(erl_type(), erl_type()) -> erl_type().
-
-t_matchstate_update_present(New, Type) ->
- case t_inf(t_matchstate(), Type) of
- ?matchstate(_, Slots) ->
- ?matchstate(New, Slots);
- _ -> ?none
- end.
-
--spec t_matchstate_update_slot(erl_type(), erl_type(), non_neg_integer()) -> erl_type().
-
-t_matchstate_update_slot(New, Type, Slot) ->
- RealSlot = Slot + 1,
- case t_inf(t_matchstate(), Type) of
- ?matchstate(Pres, Slots) ->
- NewSlots =
- case Slots of
- ?any ->
- ?any;
- ?product(Vals) when length(Vals) >= RealSlot ->
- NewTuple = setelement(RealSlot, list_to_tuple(Vals), New),
- NewVals = tuple_to_list(NewTuple),
- ?product(NewVals);
- ?product(_) ->
- ?none;
- _ when RealSlot =:= 1 ->
- New;
- _ ->
- ?none
- end,
- ?matchstate(Pres, NewSlots);
- _ ->
- ?none
- end.
-
-%%-----------------------------------------------------------------------------
%% Functions
%%
@@ -1277,7 +1164,7 @@ t_number_vals(Type) ->
t_number_vals(Type, Opaques) ->
do_opaque(Type, Opaques, fun number_vals/1).
-number_vals(?int_set(Set)) -> set_to_list(Set);
+number_vals(?int_set(Set)) -> Set;
number_vals(?number(_, _)) -> unknown;
number_vals(?opaque(_)) -> unknown;
number_vals(Other) ->
@@ -1473,10 +1360,8 @@ t_list() ->
-spec t_list(erl_type()) -> erl_type().
-t_list(?none) -> ?none;
-t_list(?unit) -> ?none;
t_list(Contents) ->
- ?list(Contents, ?nil, ?unknown_qual).
+ t_sup(t_nonempty_list(Contents), t_nil()).
-spec t_list_elements(erl_type()) -> erl_type().
@@ -1607,12 +1492,11 @@ 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{struct = S} = Opaque <- Set],
?opaque(ordsets:from_list(L));
t_widen_to_number(?product(Types)) ->
?product(list_widen_to_number(Types));
@@ -1753,7 +1637,7 @@ normalise_map_optionals([E|T], DefK, DefV, Es, F) ->
%% `#{0 => t(), pos_integer() => t()}' is to be represented by
%% `#{non_neg_integer() => t()}'.
needs_to_be_merged(?int_set(Set), DefK) ->
- [I] = set_to_list(Set),
+ [I] = Set,
Iplus = t_integer(I + 1),
Iminus = t_integer(I - 1),
InfPlus = t_inf(Iplus, DefK),
@@ -2109,9 +1993,9 @@ get_tuple_tags(_) -> [?any].
tuple_tags(?atom(?any)) -> [?any];
tuple_tags(?atom(Set)) ->
- case set_size(Set) > ?TUPLE_TAG_LIMIT of
+ case length(Set) > ?TUPLE_TAG_LIMIT of
true -> [?any];
- false -> [t_atom(A) || A <- set_to_list(Set)]
+ false -> [t_atom(A) || A <- Set]
end;
tuple_tags(_) -> [?any].
@@ -2321,6 +2205,8 @@ t_var_name(?var(Id)) -> Id.
t_has_var(?var(_)) -> true;
t_has_var(?function(Domain, Range)) ->
t_has_var(Domain) orelse t_has_var(Range);
+t_has_var(?list(Contents, ?nil, _)) ->
+ t_has_var(Contents);
t_has_var(?list(Contents, Termination, _)) ->
t_has_var(Contents) orelse t_has_var(Termination);
t_has_var(?product(Types)) -> t_has_var_list(Types);
@@ -2333,7 +2219,7 @@ t_has_var(?map(_, DefK, _)= Map) ->
t_has_var_list(map_all_values(Map)) orelse
t_has_var(DefK);
t_has_var(?opaque(Set)) ->
- t_has_var_list([O#opaque.struct || O <- set_to_list(Set)]);
+ t_has_var_list([O#opaque.struct || O <- Set]);
t_has_var(?union(List)) ->
t_has_var_list(List);
t_has_var(_) -> false.
@@ -2372,7 +2258,7 @@ t_collect_var_names(?map(_, DefK, _) = Map, Acc0) ->
Acc = t_collect_vars_list(map_all_values(Map), Acc0),
t_collect_var_names(DefK, Acc);
t_collect_var_names(?opaque(Set), Acc) ->
- t_collect_vars_list([O#opaque.struct || O <- set_to_list(Set)], Acc);
+ t_collect_vars_list([O#opaque.struct || O <- Set], Acc);
t_collect_var_names(?union(List), Acc) ->
t_collect_vars_list(List, Acc);
t_collect_var_names(_, Acc) ->
@@ -2406,7 +2292,7 @@ t_from_term(T) when is_function(T) ->
t_from_term(T) when is_integer(T) -> t_integer(T);
t_from_term(T) when is_map(T) ->
Pairs = [{t_from_term(K), ?mand, t_from_term(V)}
- || {K, V} <- maps:to_list(T)],
+ || K := V <- T],
{Stons, Rest} = lists:partition(fun({K,_,_}) -> is_singleton_type(K) end,
Pairs),
{DefK, DefV}
@@ -2466,52 +2352,6 @@ t_from_range(pos_inf, neg_inf) -> t_none().
-endif.
--spec t_from_range_unsafe(rng_elem(), rng_elem()) -> erl_type().
-
-t_from_range_unsafe(pos_inf, pos_inf) -> ?integer_pos;
-t_from_range_unsafe(neg_inf, neg_inf) -> ?integer_neg;
-t_from_range_unsafe(neg_inf, pos_inf) -> t_integer();
-t_from_range_unsafe(neg_inf, Y) -> ?int_range(neg_inf, Y);
-t_from_range_unsafe(X, pos_inf) -> ?int_range(X, pos_inf);
-t_from_range_unsafe(X, Y) when is_integer(X), is_integer(Y), X =< Y ->
- if (Y - X) < ?SET_LIMIT -> t_integers(lists:seq(X, Y));
- true -> ?int_range(X, Y)
- end;
-t_from_range_unsafe(X, Y) when is_integer(X), is_integer(Y) -> t_none();
-t_from_range_unsafe(pos_inf, neg_inf) -> t_none().
-
--spec t_is_fixnum(erl_type()) -> boolean().
-
-t_is_fixnum(?int_range(neg_inf, _)) -> false;
-t_is_fixnum(?int_range(_, pos_inf)) -> false;
-t_is_fixnum(?int_range(From, To)) ->
- is_fixnum(From) andalso is_fixnum(To);
-t_is_fixnum(?int_set(Set)) ->
- is_fixnum(set_min(Set)) andalso is_fixnum(set_max(Set));
-t_is_fixnum(_) -> false.
-
--spec is_fixnum(integer()) -> boolean().
-
-is_fixnum(N) when is_integer(N) ->
- Bits = ?BITS,
- (N =< ((1 bsl (Bits - 1)) - 1)) andalso (N >= -(1 bsl (Bits - 1))).
-
-infinity_geq(pos_inf, _) -> true;
-infinity_geq(_, pos_inf) -> false;
-infinity_geq(_, neg_inf) -> true;
-infinity_geq(neg_inf, _) -> false;
-infinity_geq(A, B) -> A >= B.
-
--spec t_is_bitwidth(erl_type()) -> boolean().
-
-t_is_bitwidth(?int_range(neg_inf, _)) -> false;
-t_is_bitwidth(?int_range(_, pos_inf)) -> false;
-t_is_bitwidth(?int_range(From, To)) ->
- infinity_geq(From, 0) andalso infinity_geq(?BITS, To);
-t_is_bitwidth(?int_set(Set)) ->
- infinity_geq(set_min(Set), 0) andalso infinity_geq(?BITS, set_max(Set));
-t_is_bitwidth(_) -> false.
-
-spec number_min(erl_type()) -> rng_elem().
number_min(Type) ->
@@ -2585,24 +2425,29 @@ expand_range_from_set(Range = ?int_range(From, To), Set) ->
%%=============================================================================
%%-----------------------------------------------------------------------------
-%% Supremum
+%% Supremum/join.
%%
-spec t_sup([erl_type()]) -> erl_type().
t_sup([]) -> ?none;
t_sup(Ts) ->
- case lists:any(fun is_any/1, Ts) of
- true -> ?any;
+ case any_any(Ts) of
+ true ->
+ ?any;
false ->
- t_sup1(Ts, [])
+ [Type|NewTs] = Ts,
+ t_sup1(NewTs, Type)
end.
-t_sup1([H1, H2|T], L) ->
- t_sup1(T, [t_sup(H1, H2)|L]);
-t_sup1([T], []) -> do_not_subst_all_vars_to_any(T);
-t_sup1(Ts, L) ->
- t_sup1(Ts++L, []).
+any_any([?any|_]) -> true;
+any_any([_|T]) -> any_any(T);
+any_any([]) -> false.
+
+t_sup1([H|T], Type) ->
+ t_sup1(T, t_sup(H, Type));
+t_sup1([], Type) ->
+ do_not_subst_all_vars_to_any(Type).
-spec t_sup(erl_type(), erl_type()) -> erl_type().
@@ -2625,15 +2470,12 @@ t_sup(?function(Domain1, Range1), ?function(Domain2, Range2)) ->
t_sup(?identifier(Set1), ?identifier(Set2)) ->
?identifier(set_union(Set1, Set2));
t_sup(?opaque(Set1), ?opaque(Set2)) ->
- sup_opaque(set_to_list(ordsets:union(Set1, Set2)));
+ sup_opaque(ordsets:union(Set1, Set2));
%%Disallow unions with opaque types
%%t_sup(T1=?opaque(_,_,_), T2) ->
%% io:format("Debug: t_sup executed with args ~w and ~w~n",[T1, T2]), ?none;
%%t_sup(T1, T2=?opaque(_,_,_)) ->
%% io:format("Debug: t_sup executed with args ~w and ~w~n",[T1, T2]), ?none;
-t_sup(?matchstate(Pres1, Slots1), ?matchstate(Pres2, Slots2)) ->
- ?matchstate(t_sup(Pres1, Pres2), t_sup(Slots1, Slots2));
-t_sup(?nil, ?nil) -> ?nil;
t_sup(?nil, ?list(Contents, Termination, _)) ->
?list(Contents, t_sup(?nil, Termination), ?unknown_qual);
t_sup(?list(Contents, Termination, _), ?nil) ->
@@ -2652,7 +2494,6 @@ t_sup(?list(Contents1, Termination1, Size1),
?list(NewContents, NewTermination, NewSize);
t_sup(?number(_, _), ?number(?any, ?unknown_qual) = T) -> T;
t_sup(?number(?any, ?unknown_qual) = T, ?number(_, _)) -> T;
-t_sup(?float, ?float) -> ?float;
t_sup(?float, ?integer(_)) -> t_number();
t_sup(?integer(_), ?float) -> t_number();
t_sup(?integer(?any) = T, ?integer(_)) -> T;
@@ -2775,7 +2616,7 @@ sup_tuples_in_set(L1, L2) ->
%% We will reach the set limit. Widen now.
[t_tuple(sup_tuple_elements(L1 ++ L2))];
?atom(Set) ->
- case set_size(Set) > ?TUPLE_TAG_LIMIT of
+ case length(Set) > ?TUPLE_TAG_LIMIT of
true ->
%% We will reach the set limit. Widen now.
[t_tuple(sup_tuple_elements(L1 ++ L2))];
@@ -2810,12 +2651,16 @@ sup_union([?none|Left1], [?none|Left2], N, Acc) ->
sup_union([T1|Left1], [T2|Left2], N, Acc) ->
sup_union(Left1, Left2, N+1, [t_sup(T1, T2)|Acc]);
sup_union([], [], N, Acc) ->
- if N =:= 0 -> ?none;
- N =:= 1 ->
+ if
+ N =:= 0 ->
+ ?none;
+ N =:= 1 ->
[Type] = [T || T <- Acc, T =/= ?none],
Type;
- N =:= length(Acc) -> ?any;
- true -> ?union(lists:reverse(Acc))
+ N =:= ?num_types_in_union ->
+ ?any;
+ true ->
+ ?union(lists:reverse(Acc))
end.
force_union(T = ?atom(_)) -> ?atom_union(T);
@@ -2829,7 +2674,6 @@ force_union(T = ?opaque(_)) -> ?opaque_union(T);
force_union(T = ?map(_,_,_)) -> ?map_union(T);
force_union(T = ?tuple(_, _, _)) -> ?tuple_union(T);
force_union(T = ?tuple_set(_)) -> ?tuple_union(T);
-force_union(T = ?matchstate(_, _)) -> ?matchstate_union(T);
force_union(T = ?union(_)) -> T.
%%-----------------------------------------------------------------------------
@@ -2891,7 +2735,7 @@ do_elements(Type0, Opaques) ->
end.
%%-----------------------------------------------------------------------------
-%% Infimum
+%% Infimum/meet.
%%
-spec t_inf([erl_type()]) -> erl_type().
@@ -2967,8 +2811,6 @@ t_inf(?map(_, ADefK, ADefV) = A, ?map(_, BDefK, BDefV) = B, _Opaques) ->
(K, _, V1, _, V2) -> {K, ?mand, t_inf(V1, V2)}
end, A, B),
t_map(Pairs, t_inf(ADefK, BDefK), t_inf(ADefV, BDefV));
-t_inf(?matchstate(Pres1, Slots1), ?matchstate(Pres2, Slots2), _Opaques) ->
- ?matchstate(t_inf(Pres1, Pres2), t_inf(Slots1, Slots2));
t_inf(?nil, ?nil, _Opaques) -> ?nil;
t_inf(?nil, ?nonempty_list(_, _), _Opaques) ->
?none;
@@ -3082,8 +2924,7 @@ inf_opaque1(T1, ?opaque(Set2)=T2, Pos, Opaques) ->
case Opaques =:= 'universe' orelse inf_is_opaque_type(T2, Pos, Opaques) of
false -> ?none;
true ->
- List2 = set_to_list(Set2),
- case inf_collect(T1, List2, Opaques, []) of
+ case inf_collect(T1, Set2, Opaques, []) of
[] -> ?none;
OpL -> ?opaque(ordsets:from_list(OpL))
end
@@ -3138,7 +2979,7 @@ inf_opaque(Set1, Set2, Opaques) ->
%% Optimization: do just one lookup.
inf_look_up(Set, Opaques) ->
[{Opaques =:= 'universe' orelse inf_is_opaque_type2(T, Opaques), T} ||
- T <- set_to_list(Set)].
+ T <- Set].
inf_is_opaque_type2(T, {match, Opaques}) ->
is_opaque_type2(T, Opaques);
@@ -3260,16 +3101,16 @@ inf_tuples_in_sets2(_, [], Acc, _Opaques) -> lists:reverse(Acc).
inf_union(U1, U2, Opaques) ->
OpaqueFun =
fun(Union1, Union2, InfFun) ->
- [_,_,_,_,_,_,_,_,Opaque,_] = Union1,
- [A,B,F,I,L,N,T,M,_,Map] = Union2,
- List = [A,B,F,I,L,N,T,M,Map],
+ ?untagged_union(_,_,_,_,_,_,_,Opaque,_) = Union1,
+ ?untagged_union(A,B,F,I,L,N,T,_,Map) = Union2,
+ List = [A,B,F,I,L,N,T,Map],
inf_union_collect(List, Opaque, InfFun, [], [])
end,
{O1, ThrowList1} =
OpaqueFun(U1, U2, fun(E, Opaque) -> t_inf(Opaque, E, Opaques) end),
- {O2, ThrowList2}
- = OpaqueFun(U2, U1, fun(E, Opaque) -> t_inf(E, Opaque, Opaques) end),
- {Union, ThrowList3} = inf_union(U1, U2, 0, [], [], Opaques),
+ {O2, ThrowList2} =
+ OpaqueFun(U2, U1, fun(E, Opaque) -> t_inf(E, Opaque, Opaques) end),
+ {Union, ThrowList3} = inf_union(U1, U2, ?none, [], [], Opaques),
ThrowList = lists:merge3(ThrowList1, ThrowList2, ThrowList3),
case t_sup([O1, O2, Union]) of
?none when ThrowList =/= [] -> throw({pos, lists:usort(ThrowList)});
@@ -3288,21 +3129,26 @@ inf_union_collect([E|L], Opaque, InfFun, InfList, ThrowList) ->
inf_union_collect(L, Opaque, InfFun, InfList, Ns ++ ThrowList)
end.
-inf_union([?none|Left1], [?none|Left2], N, Acc, ThrowList, Opaques) ->
- inf_union(Left1, Left2, N, [?none|Acc], ThrowList, Opaques);
-inf_union([T1|Left1], [T2|Left2], N, Acc, ThrowList, Opaques) ->
+inf_union([?none|Left1], [?none|Left2], Type, Acc, ThrowList, Opaques) ->
+ inf_union(Left1, Left2, Type, [?none|Acc], ThrowList, Opaques);
+inf_union([T1|Left1], [T2|Left2], Type, Acc, ThrowList, Opaques) ->
try t_inf(T1, T2, Opaques) of
- ?none -> inf_union(Left1, Left2, N, [?none|Acc], ThrowList, Opaques);
- T -> inf_union(Left1, Left2, N+1, [T|Acc], ThrowList, Opaques)
- catch throw:{pos, Ns} ->
- inf_union(Left1, Left2, N, [?none|Acc], Ns ++ ThrowList, Opaques)
+ ?none ->
+ inf_union(Left1, Left2, Type, [?none|Acc], ThrowList, Opaques);
+ T when Type =:= ?none ->
+ inf_union(Left1, Left2, T, [T|Acc], ThrowList, Opaques);
+ T ->
+ inf_union(Left1, Left2, ?union_tag, [T|Acc], ThrowList, Opaques)
+ catch
+ throw:{pos, Ns} ->
+ inf_union(Left1, Left2, Type, [?none|Acc], Ns ++ ThrowList, Opaques)
end;
-inf_union([], [], N, Acc, ThrowList, _Opaques) ->
- if N =:= 0 -> {?none, ThrowList};
- N =:= 1 ->
- [Type] = [T || T <- Acc, T =/= ?none],
- {Type, ThrowList};
- N >= 2 -> {?union(lists:reverse(Acc)), ThrowList}
+inf_union([], [], Type, Acc, ThrowList, _Opaques) ->
+ case Type of
+ ?union_tag ->
+ {?union(lists:reverse(Acc)), ThrowList};
+ _ ->
+ {Type, ThrowList}
end.
inf_bitstr(U1, B1, U2, B2) ->
@@ -3356,9 +3202,9 @@ subst_all_vars_to_any(T) ->
t_subst(T, #{}).
t_subst_aux(?var(Id), Map) ->
- case maps:find(Id, Map) of
- error -> ?any;
- {ok, Type} -> Type
+ case Map of
+ #{Id := Type} -> Type;
+ #{} -> ?any
end;
t_subst_aux(?list(Contents, Termination, Size), Map) ->
case t_subst_aux(Contents, Map) of
@@ -3389,7 +3235,7 @@ t_subst_aux(?map(Pairs, DefK, DefV), Map) ->
t_subst_aux(DefK, Map), t_subst_aux(DefV, Map));
t_subst_aux(?opaque(Es), Map) ->
List = [Opaque#opaque{struct = t_subst_aux(S, Map)} ||
- Opaque = #opaque{struct = S} <- set_to_list(Es)],
+ Opaque = #opaque{struct = S} <- Es],
?opaque(ordsets:from_list(List));
t_subst_aux(?union(List), Map) ->
?union([t_subst_aux(E, Map) || E <- List]);
@@ -3423,14 +3269,18 @@ t_unify_table_only(?var(Id1) = LHS, ?var(Id2) = RHS, VarMap) ->
VarMap#{ Id1 => LHS, Id2 => RHS }
end;
t_unify_table_only(?var(Id), Type, VarMap) ->
- case maps:find(Id, VarMap) of
- error -> VarMap#{Id => Type};
- {ok, VarType} -> t_unify_table_only(VarType, Type, VarMap)
+ case VarMap of
+ #{Id := VarType} ->
+ t_unify_table_only(VarType, Type, VarMap);
+ #{} ->
+ VarMap#{Id => Type}
end;
t_unify_table_only(Type, ?var(Id), VarMap) ->
- case maps:find(Id, VarMap) of
- error -> VarMap#{Id => Type};
- {ok, VarType} -> t_unify_table_only(VarType, Type, VarMap)
+ case VarMap of
+ #{Id := VarType} ->
+ t_unify_table_only(VarType, Type, VarMap);
+ #{} ->
+ VarMap#{Id => Type}
end;
t_unify_table_only(?function(Domain1, Range1), ?function(Domain2, Range2), VarMap) ->
VarMap1 = t_unify_table_only(Domain1, Domain2, VarMap),
@@ -3525,11 +3375,11 @@ unify_union1(?union(List), T1, T2) ->
end.
unify_union(List) ->
- [A,B,F,I,L,N,T,M,O,Map] = List,
+ ?untagged_union(A,B,F,I,L,N,T,O,Map) = List,
if O =:= ?none -> no;
true ->
S = t_opaque_structure(O),
- {yes, t_sup([A,B,F,I,L,N,T,M,S,Map])}
+ {yes, t_sup([A,B,F,I,L,N,T,S,Map])}
end.
-spec is_opaque_type(erl_type(), [erl_type()]) -> boolean().
@@ -3554,94 +3404,6 @@ is_type_name(Mod, Name, Arity, Mod, Name, Arity) ->
is_type_name(_Mod1, _Name1, _Arity1, _Mod2, _Name2, _Arity2) ->
false.
-%%t_assign_variables_to_subtype(T1, T2) ->
-%% try
-%% Dict = assign_vars(T1, T2, dict:new()),
-%% {ok, dict:map(fun(_Param, List) -> t_sup(List) end, Dict)}
-%% catch
-%% throw:error -> error
-%% end.
-
-%%assign_vars(_, ?var(_), _Dict) ->
-%% erlang:error("Variable in right hand side of assignment");
-%%assign_vars(?any, _, Dict) ->
-%% Dict;
-%%assign_vars(?var(_) = Var, Type, Dict) ->
-%% store_var(Var, Type, Dict);
-%%assign_vars(?function(Domain1, Range1), ?function(Domain2, Range2), Dict) ->
-%% DomainList =
-%% case Domain2 of
-%% ?any -> [];
-%% ?product(List) -> List
-%% end,
-%% case any_none([Range2|DomainList]) of
-%% true -> throw(error);
-%% false ->
-%% Dict1 = assign_vars(Domain1, Domain2, Dict),
-%% assign_vars(Range1, Range2, Dict1)
-%% end;
-%%assign_vars(?list(_Contents, _Termination, ?any), ?nil, Dict) ->
-%% Dict;
-%%assign_vars(?list(Contents1, Termination1, Size1),
-%% ?list(Contents2, Termination2, Size2), Dict) ->
-%% Dict1 = assign_vars(Contents1, Contents2, Dict),
-%% Dict2 = assign_vars(Termination1, Termination2, Dict1),
-%% case {Size1, Size2} of
-%% {S, S} -> Dict2;
-%% {?any, ?nonempty_qual} -> Dict2;
-%% {_, _} -> throw(error)
-%% end;
-%%assign_vars(?product(Types1), ?product(Types2), Dict) ->
-%% case length(Types1) =:= length(Types2) of
-%% true -> assign_vars_lists(Types1, Types2, Dict);
-%% false -> throw(error)
-%% end;
-%%assign_vars(?tuple(?any, ?any, ?any), ?tuple(?any, ?any, ?any), Dict) ->
-%% Dict;
-%%assign_vars(?tuple(?any, ?any, ?any), ?tuple(_, _, _), Dict) ->
-%% Dict;
-%%assign_vars(?tuple(Elements1, Arity, _),
-%% ?tuple(Elements2, Arity, _), Dict) when Arity =/= ?any ->
-%% assign_vars_lists(Elements1, Elements2, Dict);
-%%assign_vars(?tuple_set(_) = T, ?tuple_set(List2), Dict) ->
-%% %% All Rhs tuples must already be subtypes of Lhs, so we can take
-%% %% each one separately.
-%% assign_vars_lists([T || _ <- List2], List2, Dict);
-%%assign_vars(?tuple(?any, ?any, ?any), ?tuple_set(_), Dict) ->
-%% Dict;
-%%assign_vars(?tuple(_, Arity, _) = T1, ?tuple_set(List), Dict) ->
-%% case reduce_tuple_tags(List) of
-%% [Tuple = ?tuple(_, Arity, _)] -> assign_vars(T1, Tuple, Dict);
-%% _ -> throw(error)
-%% end;
-%%assign_vars(?tuple_set(List), ?tuple(_, Arity, Tag) = T2, Dict) ->
-%% case [T || ?tuple(_, Arity1, Tag1) = T <- List,
-%% Arity1 =:= Arity, Tag1 =:= Tag] of
-%% [] -> throw(error);
-%% [T1] -> assign_vars(T1, T2, Dict)
-%% end;
-%%assign_vars(?union(U1), T2, Dict) ->
-%% ?union(U2) = force_union(T2),
-%% assign_vars_lists(U1, U2, Dict);
-%%assign_vars(T, T, Dict) ->
-%% Dict;
-%%assign_vars(T1, T2, Dict) ->
-%% case t_is_subtype(T2, T1) of
-%% false -> throw(error);
-%% true -> Dict
-%% end.
-
-%%assign_vars_lists([T1|Left1], [T2|Left2], Dict) ->
-%% assign_vars_lists(Left1, Left2, assign_vars(T1, T2, Dict));
-%%assign_vars_lists([], [], Dict) ->
-%% Dict.
-
-%%store_var(?var(Id), Type, Dict) ->
-%% case dict:find(Id, Dict) of
-%% error -> dict:store(Id, [Type], Dict);
-%% {ok, _VarType0} -> dict:update(Id, fun(X) -> [Type|X] end, Dict)
-%% end.
-
%%-----------------------------------------------------------------------------
%% Subtraction.
%%
@@ -3699,14 +3461,6 @@ t_subtract(?opaque(_)=T1, T2) ->
opaque_subtract(T1, T2);
t_subtract(T1, ?opaque(_)=T2) ->
t_subtract(T1, t_opaque_structure(T2));
-t_subtract(?matchstate(Pres1, Slots1), ?matchstate(Pres2, _Slots2)) ->
- Pres = t_subtract(Pres1, Pres2),
- case t_is_none(Pres) of
- true -> ?none;
- false -> ?matchstate(Pres, Slots1)
- end;
-t_subtract(?matchstate(Present, Slots), _) ->
- ?matchstate(Present, Slots);
t_subtract(?nil, ?nil) ->
?none;
t_subtract(?nil, ?nonempty_list(_, _)) ->
@@ -3881,7 +3635,7 @@ t_subtract(T1, T2) ->
opaque_subtract(?opaque(Set1), T2) ->
List = [T1#opaque{struct = Sub} ||
- #opaque{struct = S1}=T1 <- set_to_list(Set1),
+ #opaque{struct = S1}=T1 <- Set1,
not t_is_none(Sub = t_subtract(S1, T2))],
case List of
[] -> ?none;
@@ -3903,11 +3657,11 @@ t_subtract_lists([], [], Acc) ->
-spec subtract_union([erl_type(),...], [erl_type(),...]) -> erl_type().
subtract_union(U1, U2) ->
- [A1,B1,F1,I1,L1,N1,T1,M1,O1,Map1] = U1,
- [A2,B2,F2,I2,L2,N2,T2,M2,O2,Map2] = U2,
- List1 = [A1,B1,F1,I1,L1,N1,T1,M1,?none,Map1],
- List2 = [A2,B2,F2,I2,L2,N2,T2,M2,?none,Map2],
- Sub1 = subtract_union(List1, List2, 0, []),
+ ?untagged_union(A1,B1,F1,I1,L1,N1,T1,O1,Map1) = U1,
+ ?untagged_union(A2,B2,F2,I2,L2,N2,T2,O2,Map2) = U2,
+ List1 = ?untagged_union(A1,B1,F1,I1,L1,N1,T1,?none,Map1),
+ List2 = ?untagged_union(A2,B2,F2,I2,L2,N2,T2,?none,Map2),
+ Sub1 = subtract_union(List1, List2, ?none, []),
O = if O1 =:= ?none -> O1;
true -> t_subtract(O1, ?union(U2))
end,
@@ -3916,28 +3670,28 @@ subtract_union(U1, U2) ->
end,
t_sup(O, Sub2).
--spec subtract_union([erl_type()], [erl_type()], non_neg_integer(), [erl_type()]) -> erl_type().
-
-subtract_union([T1|Left1], [T2|Left2], N, Acc) ->
+subtract_union([T1|Left1], [T2|Left2], Type, Acc) ->
case t_subtract(T1, T2) of
- ?none -> subtract_union(Left1, Left2, N, [?none|Acc]);
- T -> subtract_union(Left1, Left2, N+1, [T|Acc])
+ ?none -> subtract_union(Left1, Left2, Type, [?none|Acc]);
+ T when Type =:= none -> subtract_union(Left1, Left2, T, [T|Acc]);
+ T -> subtract_union(Left1, Left2, ?union_tag, [T|Acc])
end;
-subtract_union([], [], 0, _Acc) ->
- ?none;
-subtract_union([], [], 1, Acc) ->
- [T] = [X || X <- Acc, X =/= ?none],
- T;
-subtract_union([], [], N, Acc) when is_integer(N), N > 1 ->
- ?union(lists:reverse(Acc)).
-
-replace_nontrivial_element(El1, El2) ->
- replace_nontrivial_element(El1, El2, []).
+subtract_union([], [], Type, Acc) ->
+ case Type of
+ ?union_tag ->
+ ?union(lists:reverse(Acc));
+ _ ->
+ Type
+ end.
-replace_nontrivial_element([T1|Left1], [?none|Left2], Acc) ->
- replace_nontrivial_element(Left1, Left2, [T1|Acc]);
-replace_nontrivial_element([_|Left1], [T2|_], Acc) ->
- lists:reverse(Acc) ++ [T2|Left1].
+%% Helper for tuple and product subtraction. The second list
+%% should contain a single element that is not none. That element
+%% will replace the element in the corresponding position in the
+%% first list.
+replace_nontrivial_element([T1|Left1], [?none|Left2]) ->
+ [T1|replace_nontrivial_element(Left1, Left2)];
+replace_nontrivial_element([_|Left1], [T2|_]) ->
+ [T2|Left1].
subtract_bin(?bitstr(U1, B1), ?bitstr(U1, B1)) ->
?none;
@@ -4027,17 +3781,16 @@ t_unopaque(?product(Types), Opaques) ->
?product([t_unopaque(T, Opaques) || T <- Types]);
t_unopaque(?function(Domain, Range), Opaques) ->
?function(t_unopaque(Domain, Opaques), t_unopaque(Range, Opaques));
-t_unopaque(?union([A,B,F,I,L,N,T,M,O,Map]), Opaques) ->
+t_unopaque(?union(?untagged_union(A,B,F,I,L,N,T,O,Map)), Opaques) ->
UL = t_unopaque(L, Opaques),
UT = t_unopaque(T, Opaques),
UF = t_unopaque(F, Opaques),
- UM = t_unopaque(M, Opaques),
UMap = t_unopaque(Map, Opaques),
{OF,UO} = case t_unopaque(O, Opaques) of
?opaque(_) = O1 -> {O1, []};
Type -> {?none, [Type]}
end,
- t_sup([?union([A,B,UF,I,UL,N,UT,UM,OF,UMap])|UO]);
+ t_sup([?union([A,B,UF,I,UL,N,UT,OF,UMap])|UO]);
t_unopaque(?map(Pairs,DefK,DefV), Opaques) ->
t_map([{K, MNess, t_unopaque(V, Opaques)} || {K, MNess, V} <- Pairs],
t_unopaque(DefK, Opaques),
@@ -4066,11 +3819,12 @@ is_limited(?tuple(?any, ?any, ?any), _K) -> true;
is_limited(?tuple(Elements, _Arity, _), K) ->
if K =:= 1 -> false;
true ->
- K1 = K-1,
- lists:all(fun(E) -> is_limited(E, K1) end, Elements)
+ are_all_limited(Elements, K - 1)
end;
is_limited(?tuple_set(_) = T, K) ->
- lists:all(fun(Tuple) -> is_limited(Tuple, K) end, t_tuple_subtypes(T));
+ are_all_limited(t_tuple_subtypes(T), K);
+is_limited(?list(Elements, ?nil, _Size), K) ->
+ is_limited(Elements, K - 1);
is_limited(?list(Elements, Termination, _Size), K) ->
if K =:= 1 -> is_limited(Termination, K);
true -> is_limited(Termination, K - 1)
@@ -4079,12 +3833,11 @@ is_limited(?list(Elements, Termination, _Size), K) ->
is_limited(?function(Domain, Range), K) ->
is_limited(Domain, K) andalso is_limited(Range, K-1);
is_limited(?product(Elements), K) ->
- K1 = K-1,
- lists:all(fun(X) -> is_limited(X, K1) end, Elements);
+ are_all_limited(Elements, K - 1);
is_limited(?union(Elements), K) ->
- lists:all(fun(X) -> is_limited(X, K) end, Elements);
+ are_all_limited(Elements, K);
is_limited(?opaque(Es), K) ->
- lists:all(fun(#opaque{struct = S}) -> is_limited(S, K) end, set_to_list(Es));
+ lists:all(fun(#opaque{struct = S}) -> is_limited(S, K) end, Es);
is_limited(?map(Pairs, DefK, DefV), K) ->
%% Use the fact that t_sup() does not increase the depth.
K1 = K - 1,
@@ -4094,6 +3847,11 @@ is_limited(?map(Pairs, DefK, DefV), K) ->
andalso is_limited(DefK, K1) andalso is_limited(DefV, K1);
is_limited(_, _K) -> true.
+are_all_limited([E|Es], K) ->
+ is_limited(E, K) andalso are_all_limited(Es, K);
+are_all_limited([], _) ->
+ true.
+
t_limit_k(_, K) when K =< 0 -> ?any;
t_limit_k(?tuple(?any, ?any, ?any) = T, _K) -> T;
t_limit_k(?tuple(Elements, Arity, _), K) ->
@@ -4102,6 +3860,9 @@ t_limit_k(?tuple(Elements, Arity, _), K) ->
end;
t_limit_k(?tuple_set(_) = T, K) ->
t_sup([t_limit_k(Tuple, K) || Tuple <- t_tuple_subtypes(T)]);
+t_limit_k(?list(Elements, ?nil, Size), K) ->
+ NewElements = t_limit_k(Elements, K - 1),
+ ?list(NewElements, ?nil, Size);
t_limit_k(?list(Elements, Termination, Size), K) ->
NewTermination =
if K =:= 1 ->
@@ -4122,7 +3883,7 @@ t_limit_k(?opaque(Es), K) ->
List = [begin
NewS = t_limit_k(S, K),
Opaque#opaque{struct = NewS}
- end || #opaque{struct = S} = Opaque <- set_to_list(Es)],
+ end || #opaque{struct = S} = Opaque <- Es],
?opaque(ordsets:from_list(List));
t_limit_k(?map(Pairs0, DefK0, DefV0), K) ->
Fun = fun({EK, MNess, EV}, {Exact, DefK1, DefV1}) ->
@@ -4203,7 +3964,7 @@ t_to_string(?unit, _RecDict) ->
t_to_string(?atom(?any), _RecDict) ->
"atom()";
t_to_string(?atom(Set), _RecDict) ->
- case set_size(Set) of
+ case length(Set) of
2 ->
case set_is_element(true, Set) andalso set_is_element(false, Set) of
true -> "boolean()";
@@ -4239,16 +4000,13 @@ t_to_string(?identifier(Set), _RecDict) ->
case Set of
?any -> "identifier()";
_ ->
- flat_join([flat_format("~w()", [T]) || T <- set_to_list(Set)], " | ")
+ flat_join([flat_format("~w()", [T]) || T <- Set], " | ")
end;
t_to_string(?opaque(Set), RecDict) ->
flat_join([opaque_type(Mod, Name, Arity, S, RecDict) ||
#opaque{mod = Mod, name = Name, struct = S, arity = Arity}
- <- set_to_list(Set)],
+ <- Set],
" | ");
-t_to_string(?matchstate(Pres, Slots), RecDict) ->
- flat_format("ms(~ts,~ts)", [t_to_string(Pres, RecDict),
- t_to_string(Slots,RecDict)]);
t_to_string(?nil, _RecDict) ->
"[]";
t_to_string(?nonempty_list(Contents, Termination), RecDict) ->
@@ -4449,12 +4207,12 @@ mod_name(Mod, Name) ->
-type cache_key() :: {module(), atom(), expand_depth(),
[erl_type()], type_names()}.
-type mod_type_table() :: ets:tid().
--type mod_records() :: dict:dict(module(), type_table()).
+-type mod_records() :: #{module() => type_table()}.
-type exported_type_table() :: ets:tid().
-record(cache,
{
- types = maps:new() :: #{cache_key() => {erl_type(), expand_limit()}},
- mod_recs = {mrecs, dict:new()} :: {'mrecs', mod_records()}
+ types = #{} :: #{cache_key() => {erl_type(), expand_limit()}},
+ mod_recs = #{} :: mod_records()
}).
-opaque cache() :: #cache{}.
@@ -4471,11 +4229,11 @@ t_from_form(Form, ExpTypes, Site, RecDict, VarTab, Cache) ->
t_from_form_without_remote(Form, Site, TypeTable) ->
Module = site_module(Site),
- ModRecs = dict:from_list([{Module, TypeTable}]),
+ ModRecs = #{Module => TypeTable},
ExpTypes = replace_by_none,
VarTab = var_table__new(),
Cache0 = cache__new(),
- Cache = Cache0#cache{mod_recs = {mrecs, ModRecs}},
+ Cache = Cache0#cache{mod_recs = ModRecs},
{Type, _} = t_from_form1(Form, ExpTypes, Site, undefined, VarTab, Cache),
Type.
@@ -4574,15 +4332,18 @@ from_form_loop(Form, State, D, Limit, C, T0) ->
%%
%% It is assumed that site_module(S) can be found in MR.
+from_form(_, _S, D, L, _C) when not is_integer(D); not is_integer(L) ->
+ error(badarg);
from_form(_, _S, D, L, C) when D =< 0 ; L =< 0 ->
{t_any(), L, C};
from_form({var, _Anno, '_'}, _S, _D, L, C) ->
{t_any(), L, C};
from_form({var, _Anno, Name}, S, _D, L, C) ->
- V = S#from_form.vtab,
- case maps:find(Name, V) of
- error -> {t_var(Name), L, C};
- {ok, Val} -> {Val, L, C}
+ case S#from_form.vtab of
+ #{Name := Val} ->
+ {Val, L, C};
+ #{} ->
+ {t_var(Name), L, C}
end;
from_form({ann_type, _Anno, [_Var, Type]}, S, D, L, C) ->
from_form(Type, S, D, L, C);
@@ -4633,6 +4394,8 @@ from_form({type, _Anno, byte, []}, _S, _D, L, C) ->
{t_byte(), L, C};
from_form({type, _Anno, char, []}, _S, _D, L, C) ->
{t_char(), L, C};
+from_form({type, _Anno, dynamic, []}, _S, _D, L, C) ->
+ {t_any(), L, C};
from_form({type, _Anno, float, []}, _S, _D, L, C) ->
{t_float(), L, C};
from_form({type, _Anno, function, []}, _S, _D, L, C) ->
@@ -4880,7 +4643,7 @@ remote_from_form(Anno, RemMod, Name, Args, S, D, L, C) ->
end.
ext_types_message(MFA, Anno, Site) ->
- {MFA, {site_file(Site), erl_anno:location(Anno)}}.
+ {MFA, {site_file(Site), erl_anno:location(Anno), site_mfa(Site)}}.
remote_from_form1(RemMod, Name, Args, ArgsLen, RemDict, RemType, TypeNames,
Site, S, D, L, C) ->
@@ -5211,6 +4974,9 @@ list_check_record_fields([H|Tail], S, C) ->
site_module({_, {Module, _, _}, _}) ->
Module.
+site_mfa({_, {M, F, A}, _}) ->
+ {M, F, A}.
+
site_file({_, _, File}) ->
File.
@@ -5235,11 +5001,9 @@ cache_key(Module, Name, ArgTypes, TypeNames, D) ->
{erl_type(), expand_limit()} | 'error'.
cache_find(Key, #cache{types = Types}) ->
- case maps:find(Key, Types) of
- {ok, Value} ->
- Value;
- error ->
- error
+ case Types of
+ #{Key := Value} -> Value;
+ #{} -> error
end.
-spec cache_put(cache_key(), erl_type(), expand_limit(), cache()) -> cache().
@@ -5248,7 +5012,7 @@ cache_put(_Key, _Type, DeltaL, Cache) when DeltaL < 0 ->
%% The type is truncated; do not reuse it.
Cache;
cache_put(Key, Type, DeltaL, #cache{types = Types} = Cache) ->
- NewTypes = maps:put(Key, {Type, DeltaL}, Types),
+ NewTypes = Types#{Key => {Type, DeltaL}},
Cache#cache{types = NewTypes}.
-spec t_var_names([parse_form()]) -> [atom()].
@@ -5300,6 +5064,7 @@ t_form_to_string({type, _Anno, binary, [Base, Unit]} = Type) ->
_ -> io_lib:format("Badly formed bitstr type ~w", [Type])
end;
t_form_to_string({type, _Anno, bitstring, []}) -> "bitstring()";
+t_form_to_string({type, _Anno, dynamic, []}) -> "dynamic()";
t_form_to_string({type, _Anno, 'fun', []}) -> "fun()";
t_form_to_string({type, _Anno, 'fun', [{type, _, any}, Range]}) ->
"fun(...) -> " ++ t_form_to_string(Range);
@@ -5423,17 +5188,17 @@ is_erl_type(_) -> false.
'error' | {type_table(), cache()}.
lookup_module_types(Module, CodeTable, Cache) ->
- #cache{mod_recs = {mrecs, MRecs}} = Cache,
- case dict:find(Module, MRecs) of
- {ok, R} ->
+ #cache{mod_recs = MRecs} = Cache,
+ case MRecs of
+ #{Module := R} ->
{R, Cache};
- error ->
- try ets:lookup_element(CodeTable, Module, 2) of
+ #{} ->
+ case ets:lookup_element(CodeTable, Module, 2, error) of
+ error ->
+ error;
R ->
- NewMRecs = dict:store(Module, R, MRecs),
- {R, Cache#cache{mod_recs = {mrecs, NewMRecs}}}
- catch
- _:_ -> error
+ NewMRecs = MRecs#{Module => R},
+ {R, Cache#cache{mod_recs = NewMRecs}}
end
end.
@@ -5441,14 +5206,15 @@ lookup_module_types(Module, CodeTable, Cache) ->
'error' | {'ok', [{atom(), parse_form(), erl_type()}]}.
lookup_record(Tag, Table) when is_atom(Tag) ->
- case maps:find({record, Tag}, Table) of
- {ok, {_FileLocation, [{_Arity, Fields}]}} ->
+ Key = {record, Tag},
+ case Table of
+ #{Key := {_FileLocation, [{_Arity, Fields}]}} ->
{ok, Fields};
- {ok, {_FileLocation, List}} when is_list(List) ->
+ #{Key := {_FileLocation, List}} when is_list(List) ->
%% This will have to do, since we do not know which record we
%% are looking for.
error;
- error ->
+ #{} ->
error
end.
@@ -5456,21 +5222,25 @@ lookup_record(Tag, Table) when is_atom(Tag) ->
'error' | {'ok', [{atom(), parse_form(), erl_type()}]}.
lookup_record(Tag, Arity, Table) when is_atom(Tag) ->
- case maps:find({record, Tag}, Table) of
- {ok, {_FileLocation, [{Arity, Fields}]}} -> {ok, Fields};
- {ok, {_FileLocation, OrdDict}} -> orddict:find(Arity, OrdDict);
- error -> error
+ Key = {record, Tag},
+ case Table of
+ #{Key := {_FileLocation, [{Arity, Fields}]}} ->
+ {ok, Fields};
+ #{Key := {_FileLocation, OrdDict}} ->
+ orddict:find(Arity, OrdDict);
+ #{} ->
+ error
end.
-spec lookup_type(_, _, _) -> {'type' | 'opaque', type_value()} | 'error'.
lookup_type(Name, Arity, Table) ->
- case maps:find({type, Name, Arity}, Table) of
- error ->
- case maps:find({opaque, Name, Arity}, Table) of
- error -> error;
- {ok, Found} -> {opaque, Found}
- end;
- {ok, Found} -> {type, Found}
+ case Table of
+ #{{type, Name, Arity} := Found} ->
+ {type, Found};
+ #{{opaque, Name, Arity} := Found} ->
+ {opaque, Found};
+ #{} ->
+ error
end.
-spec type_is_defined('type' | 'opaque', atom(), arity(), type_table()) ->
@@ -5499,13 +5269,13 @@ do_opaque(?opaque(_) = Type, Opaques, Pred) ->
false -> Pred(Type)
end;
do_opaque(?union(List) = Type, Opaques, Pred) ->
- [A,B,F,I,L,N,T,M,O,Map] = List,
+ ?untagged_union(A,B,F,I,L,N,T,O,Map) = List,
if O =:= ?none -> Pred(Type);
true ->
case Opaques =:= 'universe' orelse is_opaque_type(O, Opaques) of
true ->
S = t_opaque_structure(O),
- do_opaque(t_sup([A,B,F,I,L,N,T,M,S,Map]), Opaques, Pred);
+ do_opaque(t_sup(?untagged_union(A,B,F,I,L,N,T,S,Map)), Opaques, Pred);
false -> Pred(Type)
end
end;
@@ -5536,50 +5306,23 @@ t_is_singleton(Type, Opaques) ->
%% Used to also recognize maps and tuples.
is_singleton_type(?nil) -> true;
is_singleton_type(?atom(?any)) -> false;
-is_singleton_type(?atom(Set)) ->
- ordsets:size(Set) =:= 1;
+is_singleton_type(?atom([_])) -> true;
is_singleton_type(?int_range(V, V)) -> true; % cannot happen
-is_singleton_type(?int_set(Set)) ->
- ordsets:size(Set) =:= 1;
+is_singleton_type(?int_set([_])) -> true;
is_singleton_type(_) ->
false.
-%% Returns the only possible value of a singleton type.
--spec t_singleton_to_term(erl_type(), opaques()) -> term().
-
-t_singleton_to_term(Type, Opaques) ->
- do_opaque(Type, Opaques, fun singleton_type_to_term/1).
-
-singleton_type_to_term(?nil) -> [];
-singleton_type_to_term(?atom(Set)) when Set =/= ?any ->
- case ordsets:size(Set) of
- 1 -> hd(ordsets:to_list(Set));
- _ -> error(badarg)
- end;
-singleton_type_to_term(?int_range(V, V)) -> V;
-singleton_type_to_term(?int_set(Set)) ->
- case ordsets:size(Set) of
- 1 -> hd(ordsets:to_list(Set));
- _ -> error(badarg)
- end;
-singleton_type_to_term(?tuple(Types, Arity, _)) when is_integer(Arity) ->
- lists:map(fun singleton_type_to_term/1, Types);
-singleton_type_to_term(?tuple_set([{Arity, [OnlyTuple]}]))
- when is_integer(Arity) ->
- singleton_type_to_term(OnlyTuple);
-singleton_type_to_term(?map(Pairs, ?none, ?none)) ->
- maps:from_list([{singleton_type_to_term(K), singleton_type_to_term(V)}
- || {K,?mand,V} <- Pairs]).
-
%% -----------------------------------
%% Set
%%
set_singleton(Element) ->
- ordsets:from_list([Element]).
+ [Element].
-set_is_singleton(Element, Set) ->
- set_singleton(Element) =:= Set.
+set_is_singleton(Element, [Element]) ->
+ true;
+set_is_singleton(_, _) ->
+ false.
set_is_element(Element, Set) ->
ordsets:is_element(Element, Set).
@@ -5618,29 +5361,23 @@ set_from_list(List) ->
L when L > ?SET_LIMIT -> ?any
end.
-set_to_list(Set) ->
- ordsets:to_list(Set).
-
-set_filter(Fun, Set) ->
- case ordsets:filter(Fun, Set) of
+set_filter(Pred, Set) ->
+ case [E || E <- Set, Pred(E)] of
[] -> ?none;
NewSet -> NewSet
end.
-set_size(Set) ->
- ordsets:size(Set).
-
set_to_string(Set) ->
L = [case is_atom(X) of
true -> io_lib:write_string(atom_to_list(X), $'); % stupid emacs '
false -> flat_format("~tw", [X])
- end || X <- set_to_list(Set)],
+ end || X <- Set],
flat_join(L, " | ").
set_min([H|_]) -> H.
set_max(Set) ->
- hd(lists:reverse(Set)).
+ lists:last(Set).
flat_format(F, S) ->
lists:flatten(io_lib:format(F, S)).