[erlang-questions] Dialyzer and opaque types

Jan Chochol jan.chochol@REDACTED
Tue May 27 14:54:04 CEST 2014


Hello,

We run in some problems with Dialyzer and opaque types.
Our problem can be simulated by two modules:

cat a.erl << EOF
-module(a).
-export([a/1]).

-opaque opq() :: {term()}.
-export_type([opq/0]).

-spec a(atom() | binary() | opq()) -> opq().
a(X) -> {a2(X)}.

a2({X}) -> X;
a2(X) when is_atom(X) -> X;
a2(X) when is_binary(X) -> list_to_atom(binary_to_list(X)).
EOF

cat b.erl << EOF
-module(b).
-export([b/1]).
b(X) -> a:a(X).
EOF

When we generate PLT (using Erlang 16B03-1), and analyse it, we found,
that info / contract for b:b/1 is not correctly created.

Info for a:a/1:
  [{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,
{c,tuple,[any],{1,any}},none,none,none],unknown}] ->
{{c,tuple,[any],{1,any}}
In other words:
  [atom() | binary() | {any()}] -> {any()}
Which corresponds to the specification.

Info for b:b/1:
  [{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]
-> {{c,opaque,[{opaque,a,opq,[],{c,tuple,[any],{1,any}}}],unknown}
In other words:
  [atom() | binary()] -> a:opq()
Which is wrong as it is missing possible argument of type a:opq().

When analysing problem I found this piece of code in
lib/hipe/cerl/erl_types.erl:

inf_union(U1, U2, opaque) ->
%%---------------------------------------------------------------------
%%                          Under Testing
%%----------------------------------------------------------------------
%%   OpaqueFun =
%%     fun(Union1, Union2) ->
%% [_,_,_,_,_,_,_,_,Opaque,_] = Union1,
%% [A,B,F,I,L,N,T,M,_,_R] = Union2,
%% List = [A,B,F,I,L,N,T,M],
%%         case [T || T <- List, t_inf(T, Opaque, opaque) =/= ?none] of
%%  [] -> ?none;
%%  _  -> Opaque
%% end
%%     end,
%%   O1 = OpaqueFun(U1, U2),
%%   O2 = OpaqueFun(U2, U1),
%%   Union = inf_union(U1, U2, 0, [], opaque),
%%   t_sup([O1, O2, Union]);
  inf_union(U1, U2, 0, [], opaque);

If we uncommented these lines, result of Dialyzer seems correct:
  [{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,{c,opaque,[{opaque,a,opq,[],{c,tuple,[any],{1,any}}}],unknown},none],unknown}]
-> {{c,opaque,[{opaque,a,opq,[],{c,tuple,[any],{1,any}}}],unknown}
In other words:
  [atom() | binary() | a:opq()] -> a:opq()
Which is correct.

According to git log, this part of code did not change since R13B03
(first git commit).
My question is - is it still testing code? Can it be considered stable enough?
>From my point of view, it removes false positive warning from Dialyzer
(and seems enough correct from my point of view), but I am not sure,
whether it can break something other.

Regards,
Jan Chochol



More information about the erlang-questions mailing list