What does this syntax mean?

typespecs

#1

Made a typo, but Elixir did not complain. Dialyzer gave me a headache though. What does this syntax mean?

@spec handle_response({:ok, term()} | {:error, term()}, ({:ok, term()} -> term())) ::
      term() :: {:error, String.t()}

What I really wanted was term() | {:error, String.t()}.


#2

After a few experiments

@spec handle_response({:ok, term()} | {:error, term()}, ({:ok, term()} -> term())) ::
      term() :: {:error, String.t()}

seems to simply mean

@spec handle_response({:ok, term()} | {:error, term()}, ({:ok, term()} -> term())) :: {:error, String.t()}

So it seems that the second :: simply narrows the type of term() to {:error, String.t()}.

I tried:

  • @spec main([binary()]) :: :ok as the starting “correct” function specification.
  • @spec main([binary()]) :: term() :: :ok still passed.
  • @spec main([binary()]) :: :ok :: term() failed compilation.
  • @spec main([binary()]) :: term() :: :ok failed dialyzer when the function returned :off instead of :ok.
  • @spec main(binary()) :: r when r: term() :: :ok passes.
  • @spec main(binary()) :: term() :: r when r: :ok passes.
  • @spec main(binary()) :: atom() :: :ok passes.