[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