[erlang-questions] dialyzer maybe_improper_list usage and possible internal error

Tobias Lindahl tobias.lindahl@REDACTED
Mon Nov 10 17:07:09 CET 2008


Hi Bill,

Foolish Ewe wrote:
...

> -spec(compute_generator/3 :: (Q :: pos_integer(), P ::
> maybe_improper_list(pos_integer(), pos_integer()), T ::
> non_neg_integer())-> pos_integer()).
> 
> 
> compute_generator( Q, P, T ) when (is_integer(Q) and is_list(P) and is_integer(T)) andalso ((Q > 0) and (T >= 0)) ->
> 
> Such a spec crashes the dialyzer, (I was using R12B3.22.1  on OpenSuse 11.0 at the time):

...

> 
> dialyzer: Internal problems were encountered in the analysis.
> As per the discussion by the very helpful Lestat and Pergu (actually Pergu gave this fix for the problem) on the forum, the spec should have had [] as an alternative in the second parameter to maybe_improper_list, so the spec should have read.
> -spec(compute_generator/3 :: (Q :: pos_integer(), P ::
> maybe_improper_list(pos_integer(), pos_integer() | []), T ::
> non_neg_integer())-> pos_integer()).
> 
> 
> 
> compute_generator( Q, P, T ) when (is_integer(Q) and is_list(P) and is_integer(T)) andalso ((Q > 0) and (T >= 0)) ->
> I've also sent copies to the folks I think wrote/maintain the dialyzer, so please forgive me if you get this message twice.
> 
> Having given it a bit of consideration, I think there are a few issues to consider:
> 1) The dialyzer should complain about the lame spec I made, but should not crash.

I agree. it should be handled more gracefully. What happened is that an 
assert kicked in because of a malformed type. See below for a more 
precise explanation.

> 2) However, the real problem is why did the dialyzer think that
> function used an improper_list (or maybe_improper_list)?  I'd like to
> figure out why, perhaps I have some error I can't see myself.

You use is_list(P) which only checks that P is either [] or [_|_] 
without looking at the termination. Dialyzer cannot say anything about 
the termination and gives the type maybe_improper_list().

The lists are a bit obscure in the internal representation, and some of 
the types are not really intended to be used in specs.

As Pergu pointed out to you, the termination part of a 
maybe_improper_list(X, Y) must be a supertype of [], or it would be an 
improper_list(X, Y). If the termination does not contain [] then the 
list cannot be a proper list, so the maybe_ is dropped.

Of course, this is nothing that a spec-writer should have to worry 
about, or at least get a friendly warning about rather than a crash.

> 3) I suspect my code might be stressing the dialyzer and causing it
> to have unexpected behavior (although I'm pretty reluctant to claim
> my code is anywhere near bug free).  In general, figuring out what
> the dialyzer messages really mean is sometimes tricky, and in some
> cases, I suspect the dialyzer messages do not indicate what is really
> going on.  Some static analysis tools give the values that govern
> flow of control and show just how an unexpected state can be entered,
> perhaps the dialyzer could do that as well.  Perhaps I'll post some
> examples in separate e-mails if there is sufficient interest in the
> mailing list (or if the authors are willing to take a look, perhaps
> we can see if my code is stressing the dialyzer in unexpected ways or
> perhaps my code is indeed wrong.

I am aware that sometimes the cause of the warnings are very hard to 
find. In rare cases you even need to know intricate details of the 
analysis to decipher them ;-)

If you have doubts about the warnings, just send a (preferably minimal) 
test case to me and Kostis and we can help you.

> 4) To increase the impact of a nice tool like the dialyzer, we might
> be able to author a sort of howto guide (or a wiki) to give users
> guidance in how to interpret and fix problems reported by the
> dialyzer.  E.g. I've noticed is that if a "low level" function is
> invoked by  higher level functions and they all have dialyzer errors,
> fixing the low level function will correct/change errors reported in
> thei higher level functions, so fixing those first makes sense.

Yes, this is the way to do it. Start at leaf cases in the code and fix 
the warnings about those functions, and then work your way upwards to 
the interface functions.

Indeed, there should be a howto on interpreting warnings. Unfortunately, 
I have little time to spend on such things nowadays.


> 5) If I understand, the dialyzer generates a data flow graph.  Could
> the dialyzer emit a dot version of the data flow graph suitable for
> importation into graphviz, it might be interesting to visualize that.

If you're willing to hack a bit, look at the end of the file 
lib/dialyzer/src/dialyzer_callgraph.erl where there is a debug hack to 
output the callgraph in dot format. There might be something more 
official in the future, but don't hold your breath...

Best,
Tobias

> 
> 
> Regards:
> 
> Bill M.
> 
> _________________________________________________________________
> Stay up to date on your PC, the Web, and your mobile phone with Windows Live
> http://clk.atdmt.com/MRT/go/119462413/direct/01/



More information about the erlang-questions mailing list