[erlang-questions] 12B4 dialyzer problem 3
Tobias Lindahl
tobias.lindahl@REDACTED
Thu Sep 11 13:06:31 CEST 2008
Anthony Shipman wrote:
> In a simple non-gen_server I have this state:
>
> -record(callState, {
> parent :: pid(),
> deviceID :: integer(), % the device we are making the call for
> .........
> abort :: bool(),
> callTag % reference(), a private signal
> }).
>
> -type state() :: #callState{}.
>
> This start code:
>
> State = #callState {
> parent = Parent,
> deviceID = DeviceID,
> ..............
> abort = false,
> callTag = make_ref()
> },
> spawn_link(?MODULE, enter, [State]).
>
> and a loop with this layout:
>
> -spec loopWS(state(), ref()) -> no_return().
>
> loopWS(State, RingTag) ->
> receive
> ...............
> {result, Error} ->
> case State#callState.abort of
> true ->
> exit(abort);
> false ->
> ........
> S1 = State#callState{retryCount = Count - 1},
> loopDelay(S1);
> .........
> end;
>
> abort ->
> loopWS(State#callState{abort = true}, RingTag);
>
> ....
> end
>
> where loopDelay makes a tail call back to loopWS.
>
> Dialyzer gives me this error:
>
> caller.erl:234: The call
> caller:loopWS(#callState{abort::'true'},RingTag::ref()) will fail since it
> differs in argument position 1 from the success typing arguments:
> (#callState{retryCount::pos_integer(),abort::'false'},ref())
>
> It seems to have decided already that the abort field can only ever be false
> so my attempt to set it to true is bad.
>
> The success typing seems to describe the type of S1 which has looped back to
> the type of the first argument to loopWS(). This looks like a bug in the
> reasoning to me.
Yes, this is a suspicious warning, and I wish I could fix it, but I
probably will not (at least not in the near future)
The success typing of your function can never return when you set abort
to true, thus the Dialyzer warning is correct. However, you clearly
intend the call to be allowed, so the warning should not be there. It is
a hard problem to distinguish between deliberate calls that should not
return and the ones that are there by mistake.
The solution is to add an abort function that wraps the exit(abort) and
tells Dialyzer to accept the call.
-spec(abort/2 :: () -> no_return()).
abort() -> exit(abort).
Tobias
PS I am not completely sure why you want to go another round in the loop
before the aborting, but there might be good reasons not included in the
code.
More information about the erlang-questions
mailing list