With 1.5 seems that with statements using an else block drive dialyzer crazy.
Don't know if is a dialyzer problem, but with elixir 1.4.5 it does not happens.
sample code here:
https://github.com/xadhoom/local_return/blob/master/lib/local_return.ex
Basically, when using inspect inside a fun within the with/else block , dialyzer complains about "The created fun has no local return".
I've another case when matching using :ets.lookup within with/else but I've not yet a simple reproducible example, will report later if I can draft an isolated case (basically messages like the pattern 'false' can never match the type [tuple(),...])
ok,
I've a simple example also with :ets inside with/else:
https://github.com/xadhoom/local_return/blob/master/lib/local_return_ets.ex
where dialyzer blames about:
lib/local_return_ets.ex:15: The pattern [] can never match the type 'baz' | 'foo'
lib/local_return_ets.ex:16: The pattern 'foo' can never match the type [tuple(),...]
I'm seeing this as well. I don't recall see it with 1.5.0-rc.0, but I'm rechecking now.
Thanks for the reports! If someone can reproduce it as a test in our suite here, it would be a great help. But, if not, we should be able to extract one from @xadhoom's sample app - which is already great.
This is most likely related to the tail call recursion optimizations that were added after RC 0, #6251
I can confirm that I don't see this in 1.5.0-rc.0.
Yes, this is going to be exactly the tail recursion thing. I'm not sure there's a way to fix it without either marking everything in the else handlers as generated or going for the "tuple" solution.
Here's a failing test: https://github.com/paulswartz/elixir/commit/c928fe7097430f2a2b9c4a4215331eff146331e0
Thank you @paulswartz . This has been fixed in master and in the v1.5 branch. Keep in mind you need OTP 20 because dialyzer in OTP 19.0 had some regressions and emitted warnings when it should not. Maybe OTP 19.3 is fine though.
We should have a new release in a week or two. We just need to grab the first round of regressions.
mmh seems still present on 1.5.1 (maybe a regression after the fix?)
a simple test module that shows the issue
```
defmodule Test do
def test do
with :a <- :b do
x = 42
fn -> inspect(x) end
end
end
end
@xadhoom which warning are you getting? Looking at the code, Elixir is correct in emitting a warning there.
@josevalim similar as original report, with this specific case:
lib/test.ex:3: The pattern 'a' can never match the type 'b'
lib/test.ex:5: The created fun has no local return
these are dialyzer warnings
I understand that this example is too minimal, I'll try to setup a more complete one (basically I've the same error on my code, I'll extract a meaningful one)
@josevalim here's the error, based on the test case provided here: https://github.com/paulswartz/elixir/commit/c928fe7097430f2a2b9c4a4215331eff146331e0
Dialyzer blames about
lib/test.ex:12: The created fun has no local return
require Logger
defmodule Dialyzer.With.Orig do
def with_else do
tolog = :foo
with :ok <- ok_or_error(),
:ok <- ok_or_other_error() do
:ok
else
:error ->
Logger.warn fn -> "foo #{inspect tolog}" end
:error
:other_error ->
:other_error
end
end
@spec ok_or_error() :: :ok | :error
defp ok_or_error do
Enum.random([:ok, :error])
end
@spec ok_or_other_error() :: :ok | :other_error
defp ok_or_other_error do
Enum.random([:ok, :other_error])
end
end
if the call to inspect inside the logger are removed, everything is ok.
this is not a logger issue btw, can be rephrased as:
defmodule Dialyzer.With.Orig do
def with_else do
my_ext_var = :foo
with :ok <- ok_or_error(),
:ok <- ok_or_other_error() do
:ok
else
:error ->
foo(fn -> my_ext_var end)
:error
:other_error ->
:other_error
end
end
@spec ok_or_error() :: :ok | :error
defp ok_or_error do
Enum.random([:ok, :error])
end
@spec ok_or_other_error() :: :ok | :other_error
defp ok_or_other_error do
Enum.random([:ok, :other_error])
end
defp foo(fun) do
fun.()
end
end
Most helpful comment
this is not a logger issue btw, can be rephrased as: