Dialyzer confusion over equal opaque and transparent types

Dániel Szoboszlay dszoboszlay@REDACTED
Tue Feb 25 11:12:35 CET 2020


I have a small example where Dialyzer gives a very weird warning because of
some confusion over equal opaque and transparent types. Is this a bug in
Dialyzer or is there actually some type error here that my naked eyes
cannot see?


-record(f, {f}).
-type   int() :: atom().
-opaque ext() :: int().
-opaque f() :: #f{f :: int()}.

-export_type([f/0, ext/0]).

-spec f(f()) -> ok.
f(#f{f = F}) ->

-spec x(ext()) -> ok.
x(_) ->

This module produces no Dialyzer warnings. However, a different module
using its API does:


-spec f(foo:f()) -> ok.
f(F) ->

This would generate the below warning (with OTP 22.2.3):

bar.erl:4: Invalid type specification for function bar:f/1. The success
typing is
          (foo:f()) -> 'ok'

This warning doesn't make any sense: the type specification for bar:f/1 is
the same as the success typing found by Dialyzer. The problem is actually
caused by foo:x/1's type specification: it uses the opaque ext() type
instead of the transparent int(). The two types are declared equal, so I'd
assume they can be used interchangeably within the foo module. The fact
that ext() is opaque should only matter in other modules. Yet, this
construct somehow confuses Dialyzer.

To give some context for the curious: the purpose of the equivalent ext()
and int() types is that this type shall be transparent within the
application (there are multiple modules using it), but opaque to the
outside world. So internally the application uses the int() type, but all
API functions that the outside world shall rely on use ext() instead (and
they are all in the same module that declares the opaque type, so it can
safely look into ext()-s and "convert" them into int()-s).

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20200225/3e3ae3bb/attachment.htm>

More information about the erlang-questions mailing list