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

1

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?

Bergess answered 16/5, 2016 at 13:41 Comment(6)
Do you get the same result if you pass a timeout value as the third argument to ElixirTalk.connect?Spongin
@Spongin that resolved it! Why did that cause this issue?Bergess
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.Spongin
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?Rebuff
Hi @legoscia--maybe you should extract your comment as an answer so it's obviously visible to everyone. :)Chlamys
What are the return values of ElixirTalk.connect?Tour
S
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

Schoolfellow answered 16/5, 2016 at 13:42 Comment(1)
type timeout :: integer | :infinitySkilful

© 2022 - 2024 — McMap. All rights reserved.