-module(contracts_with_subtypes). -compile(export_all). %=============================================================================== -spec extract() -> 'ok'. extract() -> case dz_extract() of {ok, Val} -> Val; error -> exit(boom) end. -spec dz_extract() -> RetValue when FileList :: something, RetValue :: {ok, FileList} | error. dz_extract() -> get(foo). %------------------------------------------------------------------------------- -spec extract2() -> 'ok'. extract2() -> case dz_extract2() of {ok, Val} -> Val; error -> exit(boom) end. -spec dz_extract2() -> RetValue when RetValue :: {ok, FileList} | error, FileList :: something. dz_extract2() -> get(foo). %=============================================================================== -spec foo1(Arg1) -> Res when Arg1 :: atom(), Res :: atom(). foo1(X) -> X. -spec foo2(Arg1) -> Res when Arg1 :: Arg2, Arg2 :: atom(), Res :: atom(). foo2(X) -> X. -spec foo3(Arg1) -> Res when Arg2 :: atom(), Arg1 :: Arg2, Res :: atom(). foo3(X) -> X. -spec foo4(Type) -> Type when is_subtype(Type, atom()). foo4(X) -> X. -spec foo5(Type :: atom()) -> Type :: atom(). foo5(X) -> X. -spec foo6(Type) -> Type when Type :: atom(). foo6(X) -> X. -spec foo7(Type) -> Type. foo7(X) -> X. %------------------------------------------------------------------------------- bar(1) -> foo1(5); bar(2) -> foo2(5); bar(3) -> foo3(5); bar(4) -> foo4(5); bar(5) -> foo5(5); bar(6) -> foo6(5); bar(7) -> foo7(5). wrong_foo6() -> b = foo6(a). %=============================================================================== -spec rec_arg(Arg) -> ok when Arg :: {a, A} | {b, B}, A :: a | {b, B}, B :: b | {a, A}. rec_arg(X) -> get(X). c(aa) -> rec_arg({a, a}); c(bb) -> rec_arg({b, b}); c(abb) -> rec_arg({a, {b, b}}); c(baa) -> rec_arg({b, {a, a}}); c(abaa) -> rec_arg({a, {b, {a, a}}}); c(babb) -> rec_arg({b, {a, {b, b}}}); c(ababb) -> rec_arg({a, {b, {a, {b, b}}}}); c(babaa) -> rec_arg({b, {a, {b, {a, a}}}}). w(ab) -> rec_arg({a, b}); % breaks the contract w(ba) -> rec_arg({b, a}); % breaks the contract w(aba) -> rec_arg({a, {b, a}}); % no longer breaks the contract w(bab) -> rec_arg({b, {a, b}}); % breaks the contract w(abab) -> rec_arg({a, {b, {a, b}}}); % no longer breaks the contract w(baba) -> rec_arg({b, {a, {b, a}}}); % no longer breaks the contract w(ababa) -> rec_arg({a, {b, {a, {b, a}}}}); w(babab) -> rec_arg({b, {a, {b, {a, b}}}}). %% For comparison: the same thing with types -type ab() :: {a, a()} | {b, b()}. -type a() :: a | {b, b()}. -type b() :: b | {a, a()}. -spec rec2(Arg) -> ok when Arg :: ab(). rec2(X) -> get(X). d(aa) -> rec2({a, a}); d(bb) -> rec2({b, b}); d(abb) -> rec2({a, {b, b}}); d(baa) -> rec2({b, {a, a}}); d(abaa) -> rec2({a, {b, {a, a}}}); d(babb) -> rec2({b, {a, {b, b}}}); d(ababb) -> rec2({a, {b, {a, {b, b}}}}); d(babaa) -> rec2({b, {a, {b, {a, a}}}}). q(ab) -> rec2({a, b}); % breaks the contract q(ba) -> rec2({b, a}); % breaks the contract q(aba) -> rec2({a, {b, a}}); % breaks the contract q(bab) -> rec2({b, {a, b}}); % breaks the contract q(abab) -> rec2({a, {b, {a, b}}}); q(baba) -> rec2({b, {a, {b, a}}}); q(ababa) -> rec2({a, {b, {a, {b, a}}}}); q(babab) -> rec2({b, {a, {b, {a, b}}}}). %=============================================================================== -type dublo(X) :: {X, X}. -type weird(X,Y) :: {X, Y, X, X}. -spec forfun(dublo(Var)) -> ok when Var :: atom(). forfun(_) -> ok. -spec forfun2(weird(Var, Var)) -> ok when Var :: atom(). forfun2(_) -> ok. %=============================================================================== -spec shallow(X) -> {ok, X} | {ok, X, file:filename()} | err1 | err2. shallow(X) -> get(X). st(X) when is_atom(X) -> case shallow(X) of err1 -> ok; err2 -> ok; {ok, X} -> ok; {ok, X, Res} -> case Res of 1 -> bad; _Other -> ok end; alpha -> bad; {ok, 42} -> ok; 42 -> bad end. %------------------------------------------------------------------------------- -spec deep(X) -> Ret when Ret :: {ok, X} | Err, Err :: err1 | err2. deep(X) -> get(X). dt(X) when is_atom(X) -> case deep(X) of err1 -> ok; err2 -> ok; {ok, X} -> ok; alpha -> bad; {ok, 42} -> ok; 42 -> bad end. %------------------------------------------------------------------------------- -type local_errors() :: err1 | err2. -spec deep2(X) -> Ret when Ret :: {ok, X} | Err, Err :: local_errors(). deep2(X) -> get(X). dt2(X) when is_atom(X) -> case deep2(X) of err1 -> ok; err2 -> ok; {ok, X} -> ok; alpha -> bad; {ok, 42} -> ok; 42 -> bad end. %------------------------------------------------------------------------------- -spec deep3(X) -> Ret when Ret :: {ok, X, file:filename()} | Err, Err :: local_errors(). deep3(X) -> get(X). dt3(X) when is_atom(X) -> case deep3(X) of err1 -> ok; err2 -> ok; {ok, X, Res} -> case Res of 1 -> bad; _Other -> ok end; {ok, X} -> bad; alpha -> bad; {ok, 42} -> bad; 42 -> bad end. %=============================================================================== -spec flat_ets_new(Name, Options) -> atom() when Name :: atom(), Options :: [Option], Option :: set | ordered_set | bag | duplicate_bag | public | protected | private | named_table | {keypos, integer()} | {heir, pid(), term()} | {heir, none} | {write_concurrency, boolean()} | {read_concurrency, boolean()} | compressed. flat_ets_new(Name, Options) -> get({Name, Options}). flat_ets_new_t() -> flat_ets_new(12,[]), flat_ets_new({a,b},[]), flat_ets_new(name,[foo]), flat_ets_new(name,{bag}), flat_ets_new(name,bag), ok. -type access() :: public | protected | private. -type type() :: set | ordered_set | bag | duplicate_bag. -spec factored_ets_new(Name, Options) -> atom() when Name :: atom(), Options :: [Option], Option :: Type | Access | named_table | {keypos,Pos} | {heir, Pid :: pid(), HeirData} | {heir, none} | Tweaks, Type :: type(), Access :: access(), Tweaks :: {write_concurrency, boolean()} | {read_concurrency, boolean()} | compressed, Pos :: pos_integer(), HeirData :: term(). factored_ets_new(Name, Options) -> get({Name, Options}). factored_ets_new_t() -> factored_ets_new(12,[]), factored_ets_new({a,b},[]), factored_ets_new(name,[foo]), factored_ets_new(name,{bag}), factored_ets_new(name,bag), ok.