[erlang-questions] 12B4 dialyzer problem 3

Tobias Lindahl <>
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