From dc844097e0828a32b1d53238e3527da1991ed711 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Fri, 24 Apr 2015 14:45:35 +0200 Subject: dialyzer: Modify the handling of parametrized opaque types In OTP 17 it is possible to mix types such as dict:dict() and dict:dict(_, _) outside of the dict module (and similarly for some other opaque types in STDLIB), but the results are unfortunately possibly invalid warnings in users' code. In OTP 18 parameterized opaque types with the same name but with different number of parameters are no longer compatible when seen from outside of the module where the types are declared. The types in STDLIB have been updated accordingly; for instance -opaque dict() :: dict(_, _). has been replaced by -type dict() :: dict(_, _). --- lib/dialyzer/test/opaque_SUITE_data/results/para | 14 ++- .../test/opaque_SUITE_data/src/para/para2.erl | 4 +- .../test/opaque_SUITE_data/src/para/para3.erl | 2 +- .../test/opaque_SUITE_data/src/para/para4.erl | 134 +++++++++++++++++++++ .../test/opaque_SUITE_data/src/para/para4_adt.erl | 108 +++++++++++++++++ lib/hipe/cerl/erl_types.erl | 54 ++++----- lib/stdlib/doc/src/array.xml | 3 - lib/stdlib/doc/src/dict.xml | 3 - lib/stdlib/doc/src/gb_sets.xml | 6 - lib/stdlib/doc/src/gb_trees.xml | 6 - lib/stdlib/doc/src/queue.xml | 3 - lib/stdlib/doc/src/sets.xml | 3 - lib/stdlib/src/array.erl | 2 +- lib/stdlib/src/dict.erl | 2 +- lib/stdlib/src/gb_sets.erl | 5 +- lib/stdlib/src/gb_trees.erl | 5 +- lib/stdlib/src/queue.erl | 2 +- lib/stdlib/src/sets.erl | 2 +- 18 files changed, 291 insertions(+), 67 deletions(-) create mode 100644 lib/dialyzer/test/opaque_SUITE_data/src/para/para4.erl create mode 100644 lib/dialyzer/test/opaque_SUITE_data/src/para/para4_adt.erl (limited to 'lib') diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/para b/lib/dialyzer/test/opaque_SUITE_data/results/para index 3aaa238de6..e50979e2f0 100644 --- a/lib/dialyzer/test/opaque_SUITE_data/results/para +++ b/lib/dialyzer/test/opaque_SUITE_data/results/para @@ -7,15 +7,25 @@ para1.erl:38: Attempt to test for equality between a term of type para1_adt:t(in para1.erl:43: Attempt to test for equality between a term of type para1_adt:t() and a term of opaque type para1_adt:t(atom()) para1.erl:48: Attempt to test for equality between a term of type para1_adt:t(integer()) and a term of opaque type para1_adt:t() para1.erl:53: The test {3,2} =:= {'a','b'} can never evaluate to 'true' -para2.erl:103: Attempt to test for equality between a term of type para2_adt:circ({{integer(),integer()},{integer(),integer()}},{{integer(),integer()},{integer(),integer()}}) and a term of opaque type para2_adt:circ({{integer(),integer()},{integer(),integer()}}) +para2.erl:103: Attempt to test for equality between a term of type para2_adt:circ(integer(),integer()) and a term of opaque type para2_adt:circ(integer()) para2.erl:117: Attempt to test for equality between a term of type para2_adt:un(atom(),integer()) and a term of opaque type para2_adt:un(integer(),atom()) para2.erl:31: The test 'a' =:= 'b' can never evaluate to 'true' para2.erl:61: Attempt to test for equality between a term of type para2_adt:c2() and a term of opaque type para2_adt:c1() para2.erl:66: The test 'a' =:= 'b' can never evaluate to 'true' -para2.erl:88: The test para2:circ({{integer(),integer()},{integer(),integer()}}) =:= para2:circ({{integer(),integer()},{integer(),integer()}},{{integer(),integer()},{integer(),integer()}}) can never evaluate to 'true' +para2.erl:88: The test para2:circ(integer()) =:= para2:circ(integer(),integer()) can never evaluate to 'true' para3.erl:28: Invalid type specification for function para3:ot2/0. The success typing is () -> 'foo' para3.erl:36: The pattern {{{17}}} can never match the type {{{{{{_,_,_,_,_}}}}}} para3.erl:55: Invalid type specification for function para3:t2/0. The success typing is () -> 'foo' para3.erl:65: The attempt to match a term of type {{{{{para3_adt:ot1(_,_,_,_,_)}}}}} against the pattern {{{{{17}}}}} breaks the opaqueness of para3_adt:ot1(_,_,_,_,_) para3.erl:68: The pattern {{{{17}}}} can never match the type {{{{{para3_adt:ot1(_,_,_,_,_)}}}}} para3.erl:74: Invalid type specification for function para3:exp_adt/0. The success typing is () -> 3 +para4.erl:21: Invalid type specification for function para4:a/1. The success typing is (dict:dict(atom() | integer(),atom() | integer()) | para4:d_all()) -> [{atom() | integer(),atom() | integer()}] +para4.erl:26: Invalid type specification for function para4:i/1. The success typing is (dict:dict(atom() | integer(),atom() | integer()) | para4:d_all()) -> [{atom() | integer(),atom() | integer()}] +para4.erl:31: Invalid type specification for function para4:t/1. The success typing is (dict:dict(atom() | integer(),atom() | integer()) | para4:d_all()) -> [{atom() | integer(),atom() | integer()}] +para4.erl:59: Attempt to test for equality between a term of type para4_adt:t(atom() | integer()) and a term of opaque type para4_adt:t(integer()) +para4.erl:64: Attempt to test for equality between a term of type para4_adt:t(atom() | integer()) and a term of opaque type para4_adt:t(atom()) +para4.erl:69: Attempt to test for equality between a term of type para4_adt:int(1 | 2 | 3 | 4) and a term of opaque type para4_adt:int(1 | 2) +para4.erl:74: Attempt to test for equality between a term of type para4_adt:int(2 | 3 | 4) and a term of opaque type para4_adt:int(1 | 2) +para4.erl:79: Attempt to test for equality between a term of type para4_adt:int(2 | 3 | 4) and a term of opaque type para4_adt:int(5 | 6 | 7) +para4.erl:84: Attempt to test for equality between a term of type para4_adt:un(3 | 4) and a term of opaque type para4_adt:un(1 | 2) +para4.erl:89: Attempt to test for equality between a term of type para4_adt:tup({_,_}) and a term of opaque type para4_adt:tup(tuple()) diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/para/para2.erl b/lib/dialyzer/test/opaque_SUITE_data/src/para/para2.erl index 09b2235fa5..4461ff291c 100644 --- a/lib/dialyzer/test/opaque_SUITE_data/src/para/para2.erl +++ b/lib/dialyzer/test/opaque_SUITE_data/src/para/para2.erl @@ -85,7 +85,7 @@ ct2_adt() -> tcirc() -> A = circ1(), B = circ2(), - A =:= B. % can never evaluate to 'true' (but the types are not OK, or?) + A =:= B. % can never evaluate to 'true' -spec circ1() -> circ(integer()). @@ -100,7 +100,7 @@ circ2() -> tcirc_adt() -> A = circ1_adt(), B = circ2_adt(), - A =:= B. % opaque attempt (one would expect them to be the same...) + A =:= B. % opaque attempt (number of parameters differs) circ1_adt() -> para2_adt:circ1(). diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/para/para3.erl b/lib/dialyzer/test/opaque_SUITE_data/src/para/para3.erl index 792ae40d39..102215b28d 100644 --- a/lib/dialyzer/test/opaque_SUITE_data/src/para/para3.erl +++ b/lib/dialyzer/test/opaque_SUITE_data/src/para/para3.erl @@ -71,7 +71,7 @@ t2_adt() -> -type exp() :: para3_adt:exp1(para3_adt:exp2()). --spec exp_adt() -> exp(). +-spec exp_adt() -> exp(). % invalid type spec exp_adt() -> 3. diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/para/para4.erl b/lib/dialyzer/test/opaque_SUITE_data/src/para/para4.erl new file mode 100644 index 0000000000..b9794672a9 --- /dev/null +++ b/lib/dialyzer/test/opaque_SUITE_data/src/para/para4.erl @@ -0,0 +1,134 @@ +-module(para4). + +-compile(export_all). + +-export_type([d_atom/0, d_integer/0, d_tuple/0, d_all/0]). + +-export_type([t/1]). + +-type ai() :: atom() | integer(). + +-type d(T) :: dict:dict(T, T). + +-opaque d_atom() :: d(atom()). +-opaque d_integer() :: d(integer()). +-opaque d_tuple() :: d(tuple()). +-opaque d_all() :: d(ai()). + +b(D) -> + a(D) ++ i(D). + +-spec a(d_atom()) -> [{atom(), atom()}]. % Invalid type spec + +a(D) -> + c(D). + +-spec i(d_integer()) -> [{integer(), integer()}]. % Invalid type spec + +i(D) -> + c(D). + +-spec t(d_tuple()) -> [{tuple(), tuple()}]. % Invalid type spec. + +t(D) -> + c(D). + +-spec c(d_all()) -> [{ai(), ai()}]. + +c(D) -> + dict:to_list(D). + + + + +-opaque t(A) :: {A, A}. + +adt_tt5() -> + I1 = adt_y1(), + I2 = adt_y3(), + I1 =:= I2. + +adt_tt6() -> + I1 = adt_y2(), + I2 = adt_y3(), + I1 =:= I2. + +adt_tt7() -> + I1 = adt_t1(), + I2 = adt_t3(), + I1 =:= I2. % opaque attempt + +adt_tt8() -> + I1 = adt_t2(), + I2 = adt_t3(), + I1 =:= I2. % opaque attempt + +adt_tt9() -> + I1 = adt_int2(), + I2 = adt_int4(), + I1 =:= I2. % opaque attempt + +adt_tt10() -> + I1 = adt_int2(), + I2 = adt_int2_4(), + I1 =:= I2. % opaque attempt + +adt_tt11() -> + I1 = adt_int5_7(), + I2 = adt_int2_4(), + I1 =:= I2. % opaque attempt + +adt_tt12() -> + I1 = adt_un1_2(), + I2 = adt_un3_4(), + I1 =:= I2. % opaque attempt + +adt_tt13() -> + I1 = adt_tup(), + I2 = adt_tup2(), + I1 =:= I2. % opaque attempt + +y3() -> + {a, 3}. + +adt_t1() -> + para4_adt:t1(). + +adt_t2() -> + para4_adt:t2(). + +adt_t3() -> + para4_adt:t3(). + +adt_y1() -> + para4_adt:y1(). + +adt_y2() -> + para4_adt:y2(). + +adt_y3() -> + para4_adt:y3(). + +adt_int2() -> + para4_adt:int2(). + +adt_int4() -> + para4_adt:int4(). + +adt_int2_4() -> + para4_adt:int2_4(). + +adt_int5_7() -> + para4_adt:int5_7(). + +adt_un1_2() -> + para4_adt:un1_2(). + +adt_un3_4() -> + para4_adt:un3_4(). + +adt_tup() -> + para4_adt:tup(). + +adt_tup2() -> + para4_adt:tup2(). diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/para/para4_adt.erl b/lib/dialyzer/test/opaque_SUITE_data/src/para/para4_adt.erl new file mode 100644 index 0000000000..407dd198a7 --- /dev/null +++ b/lib/dialyzer/test/opaque_SUITE_data/src/para/para4_adt.erl @@ -0,0 +1,108 @@ +-module(para4_adt). + +-export([t1/0, t2/0, t3/0, y1/0, y2/0, y3/0]). + +-export([int2/0, int4/0, int2_4/0, int5_7/0]). + +-export([un1_2/0, un3_4/0]). + +-export([tup/0, tup2/0]). + +-export_type([t/1, y/1, int/1, tup/1, un/1]). + +-type ai() :: atom() | integer(). + +-opaque t(A) :: {A, A}. + +-type y(A) :: {A, A}. + +-opaque int(I) :: I. + +-opaque un(I) :: atom() | I. + +-opaque tup(T) :: T. + +-spec t1() -> t(integer()). + +t1() -> + {i(), i()}. + +-spec t2() -> t(atom()). + +t2() -> + {a(), a()}. + +-spec t3() -> t(ai()). + +t3() -> + {ai(), ai()}. + +-spec y1() -> y(integer()). + +y1() -> + {i(), i()}. + +-spec y2() -> y(atom()). + +y2() -> + {a(), a()}. + +-spec y3() -> y(ai()). + +y3() -> + {ai(), ai()}. + +-spec a() -> atom(). + +a() -> + foo:a(). + +-spec i() -> integer(). + +i() -> + foo:i(). + +-spec ai() -> ai(). + +ai() -> + foo:ai(). + +-spec int2() -> int(1..2). + +int2() -> + foo:int2(). + +-spec int4() -> int(1..4). + +int4() -> + foo:int4(). + +-spec int2_4() -> int(2..4). + +int2_4() -> + foo:int2_4(). + +-spec int5_7() -> int(5..7). + +int5_7() -> + foo:int5_7(). + +-spec un1_2() -> un(1..2). + +un1_2() -> + foo:un1_2(). + +-spec un3_4() -> un(3..4). + +un3_4() -> + foo:un3_4(). + +-spec tup() -> tup(tuple()). + +tup() -> + foo:tup(). + +-spec tup2() -> tup({_, _}). + +tup2() -> + foo:tup2(). diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index e7823a596a..c7440e5ce3 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -757,7 +757,7 @@ t_opaque_from_records(RecDict) -> %% Rep = t_from_form(Type, RecDict, TmpVarDict), Rep = t_none(), % not used for anything right now Args = [t_any() || _ <- ArgNames], - skip_opaque_alias(Rep, Module, Name, Args) + t_opaque(Module, Name, Args, Rep) end, OpaqueRecDict), [OpaqueType || {_Key, OpaqueType} <- dict:to_list(OpaqueTypeDict)]. @@ -2627,13 +2627,13 @@ combine(S, T1, T2) -> #opaque{mod = Mod1, name = Name1, args = Args1} = T1, #opaque{mod = Mod2, name = Name2, args = Args2} = T2, Comb1 = comb(Mod1, Name1, Args1, S, T1), - case is_same_type_name({Mod1, Name1, Args1}, {Mod2, Name2, Args2}) of + case is_compat_opaque_names({Mod1, Name1, Args1}, {Mod2, Name2, Args2}) of true -> Comb1; false -> Comb1 ++ comb(Mod2, Name2, Args2, S, T2) end. comb(Mod, Name, Args, S, T) -> - case is_same_name(Mod, Name, Args, S) of + case can_combine_opaque_names(Mod, Name, Args, S) of true -> ?opaque(Set) = S, Set; @@ -2641,10 +2641,10 @@ comb(Mod, Name, Args, S, T) -> [T#opaque{struct = S}] end. -is_same_name(Mod1, Name1, Args1, - ?opaque([#opaque{mod = Mod2, name = Name2, args = Args2}])) -> - is_same_type_name({Mod1, Name1, Args1}, {Mod2, Name2, Args2}); -is_same_name(_, _, _, _) -> false. +can_combine_opaque_names(Mod1, Name1, Args1, + ?opaque([#opaque{mod = Mod2, name = Name2, args = Args2}])) -> + is_compat_opaque_names({Mod1, Name1, Args1}, {Mod2, Name2, Args2}); +can_combine_opaque_names(_, _, _, _) -> false. %% Combining two lists this way can be very time consuming... %% Note: two parameterized opaque types are not the same if their @@ -2678,18 +2678,31 @@ inf_opaque_types(IsOpaque1, ModNameArgs1, T1, #opaque{struct = S2}=T2, case Opaques =:= 'universe' orelse - is_same_type_name(ModNameArgs1, ModNameArgs2) + is_compat_opaque_names(ModNameArgs1, ModNameArgs2) of true -> t_inf(S1, S2, Opaques); false -> case {IsOpaque1, IsOpaque2} of - {true, true} -> t_inf(S1, S2, Opaques); - {true, false} -> t_inf(S1, ?opaque(set_singleton(T2)), Opaques); - {false, true} -> t_inf(?opaque(set_singleton(T1)), S2, Opaques); + {true, true} -> t_inf(S1, S2, Opaques); + {true, false} -> t_inf(S1, ?opaque(set_singleton(T2)), Opaques); + {false, true} -> t_inf(?opaque(set_singleton(T1)), S2, Opaques); {false, false} -> t_none() end end. +is_compat_opaque_names(ModNameArgs, ModNameArgs) -> true; +is_compat_opaque_names({Mod,Name,Args1}, {Mod,Name,Args2}) -> + is_compat_args(Args1, Args2); +is_compat_opaque_names(_, _) -> false. + +is_compat_args([A1|Args1], [A2|Args2]) -> + is_compat_arg(A1, A2) andalso is_compat_args(Args1, Args2); +is_compat_args([], []) -> true; +is_compat_args(_, _) -> false. + +is_compat_arg(A, A) -> true; +is_compat_arg(A1, A2) -> t_is_any(A1) orelse t_is_any(A2). + -spec t_inf_lists([erl_type()], [erl_type()]) -> [erl_type()]. t_inf_lists(L1, L2) -> @@ -4228,16 +4241,12 @@ type_from_form(Name, Args, TypeNames, ET, M, MR, V, D, L) -> end, Rep1 = choose_opaque_type(Rep, Type), Args2 = [subst_all_vars_to_any(ArgType) || ArgType <- ArgTypes], - {skip_opaque_alias(Rep1, Module, Name, Args2), L2}; + {t_opaque(Module, Name, Args2, Rep1), L2}; error -> Msg = io_lib:format("Unable to find type ~w/~w\n", [Name, ArgsLen]), throw({error, Msg}) end. -skip_opaque_alias(?opaque(_) = T, _Mod, _Name, _Args) -> T; -skip_opaque_alias(T, Module, Name, Args) -> - t_opaque(Module, Name, Args, T). - remote_from_form(RemMod, Name, Args, TypeNames, ET, M, MR, V, D, L) -> {ArgTypes, L1} = list_from_form(Args, TypeNames, ET, M, MR, V, D, L), if @@ -4280,7 +4289,7 @@ remote_from_form(RemMod, Name, Args, TypeNames, ET, M, MR, V, D, L) -> {t_any(), L1} end, NewRep1 = choose_opaque_type(NewRep, Type), - {skip_opaque_alias(NewRep1, Mod, Name, ArgTypes), L2}; + {t_opaque(Mod, Name, ArgTypes, NewRep1), L2}; error -> Msg = io_lib:format("Unable to find remote type ~w:~w()\n", [RemMod, Name]), @@ -4680,17 +4689,6 @@ do_opaque(?union(List) = Type, Opaques, Pred) -> do_opaque(Type, _Opaques, Pred) -> Pred(Type). -is_same_type_name(ModNameArgs, ModNameArgs) -> true; -is_same_type_name({Mod, Name, Args1}, {Mod, Name, Args2}) -> - all_any(Args1) orelse all_any(Args2); -is_same_type_name(_ModNameArgs1, _ModNameArgs2) -> - false. - -all_any([]) -> true; -all_any([T|L]) -> - t_is_any(T) andalso all_any(L); -all_any(_) -> false. - map_keys(?map(Pairs)) -> [K || {K, _} <- Pairs]. diff --git a/lib/stdlib/doc/src/array.xml b/lib/stdlib/doc/src/array.xml index b03a2fa0cc..af23cd95d9 100644 --- a/lib/stdlib/doc/src/array.xml +++ b/lib/stdlib/doc/src/array.xml @@ -93,9 +93,6 @@ the default value cannot be confused with the values of set entries.

- -

array() is equivalent to array(term()).

-
diff --git a/lib/stdlib/doc/src/dict.xml b/lib/stdlib/doc/src/dict.xml index 0771682a25..b456b97578 100644 --- a/lib/stdlib/doc/src/dict.xml +++ b/lib/stdlib/doc/src/dict.xml @@ -46,9 +46,6 @@ - -

dict() is equivalent to dict(term(), term()).

-
diff --git a/lib/stdlib/doc/src/gb_sets.xml b/lib/stdlib/doc/src/gb_sets.xml index 405bae5698..99e92d8680 100644 --- a/lib/stdlib/doc/src/gb_sets.xml +++ b/lib/stdlib/doc/src/gb_sets.xml @@ -120,9 +120,6 @@ - -

set() is equivalent to set(term()).

-
@@ -130,9 +127,6 @@ - -

iter() is equivalent to iter(term()).

-
diff --git a/lib/stdlib/doc/src/gb_trees.xml b/lib/stdlib/doc/src/gb_trees.xml index 82167e1083..99ca2d6a9a 100644 --- a/lib/stdlib/doc/src/gb_trees.xml +++ b/lib/stdlib/doc/src/gb_trees.xml @@ -64,9 +64,6 @@ - -

tree() is equivalent to tree(term(), term()).

-
@@ -74,9 +71,6 @@ - -

iter() is equivalent to iter(term(), term()).

-
diff --git a/lib/stdlib/doc/src/queue.xml b/lib/stdlib/doc/src/queue.xml index 9c994154d4..f689412988 100644 --- a/lib/stdlib/doc/src/queue.xml +++ b/lib/stdlib/doc/src/queue.xml @@ -95,9 +95,6 @@ - -

queue() is equivalent to queue(term()).

-
diff --git a/lib/stdlib/doc/src/sets.xml b/lib/stdlib/doc/src/sets.xml index 4a31648f8f..eecddb7fd4 100644 --- a/lib/stdlib/doc/src/sets.xml +++ b/lib/stdlib/doc/src/sets.xml @@ -50,9 +50,6 @@ - -

set() is equivalent to set(term()).

-
diff --git a/lib/stdlib/src/array.erl b/lib/stdlib/src/array.erl index 10d2ccea45..f98a587c55 100644 --- a/lib/stdlib/src/array.erl +++ b/lib/stdlib/src/array.erl @@ -164,7 +164,7 @@ elements :: elements(_) %% the tuple tree }). --opaque array() :: array(term()). +-type array() :: array(term()). -opaque array(Type) :: #array{default :: Type, elements :: elements(Type)}. diff --git a/lib/stdlib/src/dict.erl b/lib/stdlib/src/dict.erl index 5a9f63c5e2..d2af9554a1 100644 --- a/lib/stdlib/src/dict.erl +++ b/lib/stdlib/src/dict.erl @@ -70,7 +70,7 @@ }). --opaque dict() :: dict(_, _). +-type dict() :: dict(_, _). -opaque dict(Key, Value) :: #dict{segs :: segs(Key, Value)}. diff --git a/lib/stdlib/src/gb_sets.erl b/lib/stdlib/src/gb_sets.erl index d3fbd542f7..d099737d8f 100644 --- a/lib/stdlib/src/gb_sets.erl +++ b/lib/stdlib/src/gb_sets.erl @@ -203,11 +203,10 @@ -export_type([set/0, set/1, iter/0, iter/1]). -type gb_set_node(Element) :: 'nil' | {Element, _, _}. --type gb_set_node() :: gb_set_node(_). -opaque set(Element) :: {non_neg_integer(), gb_set_node(Element)}. --opaque set() :: set(_). +-type set() :: set(_). -opaque iter(Element) :: [gb_set_node(Element)]. --opaque iter() :: [gb_set_node()]. +-type iter() :: iter(_). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/stdlib/src/gb_trees.erl b/lib/stdlib/src/gb_trees.erl index 259e8f718b..2cbfd8fd2a 100644 --- a/lib/stdlib/src/gb_trees.erl +++ b/lib/stdlib/src/gb_trees.erl @@ -160,11 +160,10 @@ -type gb_tree_node(K, V) :: 'nil' | {K, V, gb_tree_node(K, V), gb_tree_node(K, V)}. --type gb_tree_node() :: gb_tree_node(_, _). -opaque tree(Key, Value) :: {non_neg_integer(), gb_tree_node(Key, Value)}. --opaque tree() :: tree(_, _). +-type tree() :: tree(_, _). -opaque iter(Key, Value) :: [gb_tree_node(Key, Value)]. --opaque iter() :: [gb_tree_node()]. +-type iter() :: iter(_, _). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/stdlib/src/queue.erl b/lib/stdlib/src/queue.erl index 472d503b99..d2e6848258 100644 --- a/lib/stdlib/src/queue.erl +++ b/lib/stdlib/src/queue.erl @@ -48,7 +48,7 @@ -opaque queue(Item) :: {list(Item), list(Item)}. --opaque queue() :: queue(_). +-type queue() :: queue(_). %% Creation, inspection and conversion diff --git a/lib/stdlib/src/sets.erl b/lib/stdlib/src/sets.erl index 167a676281..041d281148 100644 --- a/lib/stdlib/src/sets.erl +++ b/lib/stdlib/src/sets.erl @@ -70,7 +70,7 @@ segs :: segs(_) % Segments }). --opaque set() :: set(_). +-type set() :: set(_). -opaque set(Element) :: #set{segs :: segs(Element)}. -- cgit v1.2.3