[erlang-bugs] Dialyzer unmatched_returns generates false positives

Kostis Sagonas kostis@REDACTED
Tue Apr 12 10:50:53 CEST 2011


Adam Lindberg wrote:
> Hi,
> 
> Using the option unmatched_returns in dialyzer seems to generate false 
> positives inside list comprehensions. Consider the following code:
> 
> f() -> ok.
> 
> g() -> [f() || _E <- lists:seq(1,3)], ok.
> 
> It generates the following warning:
> 
> Expression produces a value of type ['ok'], but this value is unmatched.
> 
> This is okay, because we don't actually match on the return from f(). I 
> would think that the following fix removes the warning, but it does not:
> 
> g() -> [ok = f() || E <- lists:seq(1,3)], ok.
> 
> For a list of variable length, the only alternative would be the 
> following (which dialyzer does not complain about):
> 
> g() -> lists:all(fun(ok) -> true end, [ok = f() || _E <- 
> lists:seq(1,3)]), ok.
> 
> But it doesn't have the same behavior (will generate a function clause 
> error instead of a badmatch error if something fails).

You misunderstand both the warning and how to fix it.  Dialyzer does not 
complain that the f() return is unmatched, but it complains that the 
return from the list comprehension is unmatched.  Note that the warning 
does not say 'ok' but it says ['ok'] (i.e., that a list of 'ok' values 
is unmatched).  And indeed it is as far as *Erlang* is concerned.

Now, it's true that the BEAM compiler performs an optimization that does 
not construct this list, but this is not something that is reflected in 
the operational semantics of Erlang.  Because dialyzer is based on Core 
Erlang and aims to be compiler independent (it's conceivable that in the 
future some other compiler may take the place of BEAM) it does not model 
its optimizations.

Anyway, this is not a false positive. It's a bit unfortunate, but it's 
intentional.  The proper way to write this in order not to get the 
dialyzer warning with unmatched return is to write the following:

    g() ->
      lists:foreach(fun(_E) -> f() end, lists:seq(1,3)),
      ok.

If you want to write it with the list comprehension, the kosher way to 
write it is:

    g() ->
      _ = [f() || E <- lists:seq(1,3)],
      ok.

Kostis



More information about the erlang-bugs mailing list