[erlang-questions] 12B4 dialyzer problem 4

Kostis Sagonas <>
Thu Sep 11 14:20:49 CEST 2008


Anthony Shipman wrote:
> I have some functions in a gen_server:
> 
> enableConnecting(State, T) ->
>     {ok, TRef} = timer:send_after(T, State#state.timerRef),
>     State#state{timer = TRef}.
> 
> disableConnecting(State) ->
>     case State#state.timer of
>     undefined ->
> 	State;
> 
> (285)  TRef ->
> 	timer:cancel(TRef),
> 	State#state{timer = undefined}
>     end.
> 
> Dialyzer says
> 
> muConnector.erl:285: The variable TRef can never match since previous clauses 
> completely covered the type 'undefined'
> 
> enableConnecting() is definitely reachable so how can this be so?  
> 

  [... Anthony has sent me his complete program in a private mail ...]

In that program I see that disableConnecting/1 is a function which is 
local to the module; it's not exported.  The only place where it is 
called is in a function which reads:

onUp(State) ->
     #state{locn = Locn, subscribers = Subs, isUp = Up, waiters = W} = 
State,
     S1 = if
	not Up ->
	    %% ?INFO_("muConnector: MU is up"),
	    lists:foreach(fun(Sub) -> Sub!{muUp, Locn} end, Subs),
	    lists:foreach(fun(From) -> gen_server:reply(From, ok) end, W),
	    State#state{isUp = true, waiters = []};
	true ->
	    State
     end,
     disableConnecting(S1).

If one looks closely in this function, she can observe that the 'timer' 
field is never initialized so it defaults to 'undefined'.  This happens 
on all paths to the disableConnecting(S1) call.

Dialyzer has every right to claim that State#state.timer will always be 
'undefined' and the second clause (with TRef) will never be reached.

One more subtle bug uncovered.

Kostis



More information about the erlang-questions mailing list