[erlang-questions] picky dialyzer
Kostis Sagonas
kostis@REDACTED
Thu Jan 13 12:09:51 CET 2011
Ulf Wiger wrote:
> This has me confused:
>
> Compiled src/jobs_server.erl
> ==> jobs (analyze)
> jobs_server.erl:1251: The pattern {'queue', _, _, {'producer', _}, _, _, _, _, _, _, _, _, _, _} can never match the type #queue{mod::atom(),type::'fifo' | #action{a::'approve' | 'reject'} | #passive{type::'fifo'},group::atom(),...}
>
> The line in question is
>
> q_is_empty(#queue{type = #producer{}}) -> false;
>
>
> The #queue{} record definition is:
>
> -record(producer, {f :: mfa() | function()}).
> -record(passive , {type = fifo :: fifo}).
> -record(action , {a = approve :: approve | reject}).
>
> -record(queue, {name :: any(),
> mod :: atom(),
> type = fifo :: fifo | #producer{} | #passive{} | #action{},
> group :: atom(),
> …}
>
> Why does dialyzer think that #producer{} is not a valid member of
> the type def for the 'type' attribute?
Because it is very clever! :D
You are looking at the tree and you are missing the forest... You are
concentrating at the type definitions you have added, when you should be
examining the code you wrote. The code of q_is_empty/1 reads:
q_is_empty(#queue{type = #producer{}}) -> false;
q_is_empty(#queue{mod = Mod} = Q) -> Mod:is_empty(Q).
and this is a module-local function, meaning it will only be used from
within this module. The only place in the module where there are calls
to this function is from;
check_queue(#queue{type = #producer{}} = Q, TS, S) ->
do_check_queue(Q, TS, S);
check_queue(Q, TS, S) ->
case q_is_empty(Q) of
true ->
...;
false ->
...
end.
At the point where the call to q_is_empty/1 is, dialyzer knows that Q
will be a #queue{} record where type is not a #producer{}. In other
words, there will never be any calls that will match the first clause of
q_is_empty/1. So, this clause is unreachable.
> The funny thing is that if I rename the #producer{} record to e.g.
> #prod{} or #produce{}, dialyzer picks it up (but generates a bunch of
> other problems, partly because the change wasn't done consistently throughout).
>
> This (or practically the same warning) can be reproduced by pulling the
> latest version of http://github.com/esl/jobs and running ./rebar analyze
Well, if I pull the latest version from this repository, I get many more
dialyzer warnings when I analyze this file. For example, dialyzer
complains that
jobs_server.erl:991: The call
erlang:spawn_monitor(M::atom(),F::atom(),A::byte()) will never return
since it differs in the 3rd argument from the success typing arguments:
(atom(),atom(),[any()])
and it is of course right.
The problem is that your #producer{} definition is a buggy. It reads:
-record(producer, {f = {erlang,error,[undefined_producer]} :: mfa() |
function()}).
mfa() is an alias for {atom(),atom(),byte()}.
You want to write {atom(),atom(),[term()]} instead of mfa() there.
Cheers,
Kostis
More information about the erlang-questions
mailing list