8

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?

Will Sewell
  • 2,593
  • 2
  • 20
  • 39
  • 2
    Do you get the same result if you pass a timeout value as the third argument to `ElixirTalk.connect`? – legoscia May 16 '16 at 14:11
  • @legoscia that resolved it! Why did that cause this issue? – Will Sewell May 16 '16 at 15:30
  • 6
    Looking at [the source](https://github.com/jsvisa/elixir_talk/blob/master/lib/elixir_talk.ex#L16), 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
  • 1
    Nice! This should also be manifesting as a warning for `ElixirTalk.connect/2` itself, but since it is probably in the PLT it is not shown? – aronisstav May 16 '16 at 16:17
  • 4
    Hi @legoscia--maybe you should extract your comment as an answer so it's obviously visible to everyone. :) – Onorio Catenacci May 17 '16 at 13:53
  • 1
    What are the return values of `ElixirTalk.connect`? – rvirding May 17 '16 at 14:01

1 Answers1

1

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

Sinc
  • 553
  • 1
  • 8
  • 31