Will Sewell
Will Sewell

Reputation: 2643

Dialyzer says function will never be called, even though it is

I am using the elixir_talk library. After connecting I want to call a private function once connected to beanstalkd. I just added typespecs and ran Dialyzer (via dialyxir). I get the errors:

my_module.ex:3: The specification for 'Elixir.MyModule':f/0 states that the function might also return 'ok' | {'error',_} but the inferred return is none()
my_module.ex:4: Function f/0 has no local return
my_module.ex:14: Function g/1 will never be called

The minimal example I could find that produces this is

defmodule MyModule do
  @spec f() :: :ok | {:error, term}
  def f() do
    case ElixirTalk.connect('127.0.0.1', 11300) do
      {:ok, conn} ->
        g(conn)
      {:error, err} ->
        {:error, err}
    end
  end

  @spec g(pid) :: :ok
  defp g(pid) do
    :ok
  end
end

If I replace the call to ElixirTalk.connect with a call to spawn instead, Dialyzer no longer reports any problems.

defmodule MyModule do
  @spec f() :: :ok
  def f() do
    x = spawn fn -> :done end
    g(x)
  end

  @spec g(pid) :: :ok
  defp g(pid) do
    :ok
  end
end

Does anyone know why Dialyzer is getting confused here?

Upvotes: 8

Views: 1927

Answers (1)

Sinc
Sinc

Reputation: 671

Looking at the source, the type spec says that the third argument is always an integer, even though the default value is the atom infinity. Thus, a call to ElixirTalk.connect with infinite timeout would be against the type spec. In Erlang you'd fix this by specifying the type as timeout() instead, which allows both integers and infinity; not sure how that translates to Elixir. – legoscia May 16 '16 at 15:56

Upvotes: 1

Related Questions