I have recently started learning Elixir, and while playing around with typespecs within a Mix project I stumbled upon some Dialyzer warnings I don't quite understand; the following code is a fairly minimal example:
defmodule Foo do
@opaque bar :: [integer]
@spec new() :: bar
def new() do [] end
@type baz :: [integer]
@spec old() :: baz
def old() do [] end
end
When I run mix dialyzer with underspecs among the flags, I get these:
lib/minimal.ex:9:contract_supertype
Type specification is a supertype of the success typing.
Function:
Foo.new/0
Type specification:
@spec new() :: bar()
Success typing:
@spec new() :: Foo.bar()
________________________________________________________________________________
lib/minimal.ex:9:contract_supertype
Type specification is a supertype of the success typing.
Function:
Foo.old/0
Type specification:
@spec old() :: baz()
Success typing:
@spec old() :: []
Now, since [] (the empty list type) is a subtype of [integer] I do expect the spec for old() to be a supertype of the inferred type, although I'd prefer there was a way to "cast" the empty list to the [integer] type, or even better that the underspecs option actually cared about functions whose spec'd inputs are laxer than the success type and spec'd output is stricter than the success type (i.e., to warn when the spec'd function type is a subtype of the success function type, with the usual notion that function types are contravariant in their input types and covariant in their output type, rather than considering ([integer] -> nil) a supertype of ([] -> nil))...
But the weird one is the error for new(): the success typing seems exactly the type I specified in the spec, so how can the latter be a supertype? And also, apparently using an opaque type changes the success types, how does this work exactly? I couldn't find any in-depth description of what defining types as opaque changes in terms of typechecking and inference...
I'd be grateful to anybody more familiar with Elixir's typing who could offer an explanation or pointers to more information (especially since the official documentation around typespecs is fairly thin).