aboutsummaryrefslogblamecommitdiffstats
path: root/lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes.erl
blob: d7dfd9752ed75511062525093e4395fbd5da98d2 (plain) (tree)








































































































                                                                                





                                                                     


                                           




























                                                  






























                                                                                
                       
















                                                                                
                       


















                                                                                
                       


















































































                                                                                
-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.