Question

Here is some code with an error which I think Dialyzer should be able to spot:

-module(myapp_thing).

-spec exists(pos_integer()) -> yes | no.
exists(Id) ->
    myapp_mnesia:thing_exists(Id).

 

-module(myapp_mnesia).

thing_exists(Id) ->
    Exists = fun() -> 
                     case mnesia:read({thing, Id}) of
                         [] -> false;
                         _ ->  true
                     end
             end,
    mnesia:activity(transaction, Exists).

 

myapp_thing:exists/1 is specified as returning yes | no, but the return type will actually be true | false (i.e., boolean()), which is what is returned from myapp_mnesia:thing_exists/1.

However, running Dialyzer on myapp passes it without warnings.

If I change myapp_mnesia:thing_exists/1 to just return true I get an appropriate warning; similarly if I add the right spec:

-spec session_exists(pos_integer()) -> boolean().

But it looks like Dialyzer can't look inside the mnesia transaction function Exists, or for some other reason can't infer a return type for thing_exists.

So, are mnesia transaction functions a barrier for Dialyzer, or is there a more general barrier to Dialyzer's return type inference?

Was it helpful?

Solution

In mnesia_tm:execute_transaction, the provided fun is being called inside a catch, which means that the return type collapses into term() as far as Dialyzer is concerned. Thus Dialyzer is unable to conclude that the return type of mnesia:activity/2 is the same as that of the provided function, and thus needs an explicit type spec to that effect.

Besides, I believe that Dialyzer generally never infers a return value type based on the return value of a function provided as an argument. For example, with this module:

-module(foo).

-export([foo/1]).

foo(F) ->
    F(42).

typer shows the following:

$ typer /tmp/foo.erl

%% File: "/tmp/foo.erl"
%% --------------------
-spec foo(fun((_) -> any())) -> any().

though if I add the explicit type spec -spec foo(fun((_) -> X)) -> X., then typer accepts it.

(I'm sure the Dialyzer developers will have a more complete and insightful answer to this.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top