[erlang-questions] why can't dialyzer see that my spec is a lie?

Kostis Sagonas kostis@REDACTED
Sun Feb 13 13:22:24 CET 2011


Matthias Lang wrote:
> Hi,
> 
> Running the example below through dialyzer R14B01:
> 
>   143> dialyzer:run([{from, src_code}, {files, ["minimal.erl"]}]). 
>   []
> 
> I was hoping Dialyzer would complain that my spec (line 18) is a lie.
> 
> Cut down, but compilable, code below. Changing "almost anything" results
> in a good warning, e.g. if I comment out the recursive step (line 13):
> 
>   145> dialyzer:run([{from, src_code}, {files, ["minimal.erl"]}]).
>   [{warn_contract_types,{"/tmp/minimal.erl",17},
>                       {extra_range,[minimal,parse_and_execute,1,"'quit'",
>                                     "{_,_}"]}}]
> 
> What's going on? I'm stumped.

In program analysis tools one needs to choose between soundness for 
correctness (i.e., find all errors and then some) and soundness for 
defect detection (i.e., find only true discrepancies but raise no false 
alarms).

Dialyzer has opted for the latter, which means that it can occasionally 
fail to report some discrepancies between the code and its intended uses 
(as documented for example in programmer-supplied specs). That's what's 
happening here.

In your program, dialyzer infers a return type of any() for your 
parse_and_execute/1 function and cannot see that it is invalid 
(actually, even the warning you get when you do the change you suggest 
in your mail is not the "right" one).  I think this happens because it 
does not propagate information about closures across functions, esp. 
when an infinite loop is involved as in your program.

We will look at this issue (thanks for reporting it) and try to fix it 
in a future dialyzer version.

Kostis

> ----------------------------------------------------------------------
> -module(minimal).
> -export([start/0]).
> 
> -record(state, {commands}).
> 
> start() ->
>     Fun = fun() -> {quit, "string"} end,
>     server_loop(#state{commands=Fun}).
> 
> server_loop(State) ->
>     try
> 	{New_state, _} = parse_and_execute(State),
> 	server_loop(New_state)
>     catch
> 	_:_ -> ok
>     end.
> 
> -spec parse_and_execute(any()) -> {#state{}, string()} | 'quit'.
> 
> parse_and_execute(State) ->
>     Fun = State#state.commands,
>     Fun().
> 
> 
> 
> ________________________________________________________________
> erlang-questions (at) erlang.org mailing list.
> See http://www.erlang.org/faq.html
> To unsubscribe; mailto:erlang-questions-unsubscribe@REDACTED



More information about the erlang-questions mailing list