Consider the following code:
defmodule Foo do
@typep foo :: integer
@type bar :: foo
@typep re :: integer
@type mi :: float | re
@type la :: mi | nil
@spec baz(integer) :: foo
def baz(bat), do: bat
end
This code presents several problems, and in my opinion should generate
at least two different compiler warnings, or the semantic of typep
should be changed slightly.
1) When referencing Foo.bar in @specs externally, Dialyzer will
complain (correctly) that it cannot find Foo.foo, since that is not in
the namespace of the code using Foo.bar. This puts Foo.foo into a
pseudo-private state, where other code can see it via Foo.bar but
never actually use Foo.bar for typespecs because it references
Foo.foo.
Proposed warning: Cannot reference @typep in @type.
2) Though a more general case of 1, one should not be able to
indirectly reference a @typep via @type, as in the case of Foo.la
referencing Foo.re. I call this a shadowed @typep, but
have no particular claims to this name being optimal. Feel free to
change.
Proposed warning: Cannot reference shadowed @typep in @type.
3) Foo.bat should not, as a def, be able to reference a @typep in its
@spec. Supposing this were in an @callback, for example, there would
be no way to have an @spec in the implementation for the @behaviour
that would actually work, for similar reasons as above, since you
could never reference Foo.foo in a module besides Foo.
Proposed warning: Cannot reference @typep in @spec for def.
However, one could argue that a simple change in the semantic of
@typep would alleviate all of these issues. If @typep had a sort of
unfolding behavior, where it was simply a shorthand for types locally,
that eventually become their longer forms. So for example someone
referencing Foo.la would see integer | float | nil. I do not
personally like this, it seems rather counterintuitive to me, but I
can see an argument to be made for it.
As an example of how this was inconvenient for me recently, in Ecto
one can set up a module as a logger for Ecto.Repo queries.
would generate a warning when running dialyzer of:
Unknown types:
'Elixir.IO.ANSI':ansicode/0