[erlang-questions] Dialyzer and record MatchSpec warnings

Kostis Sagonas kostis@REDACTED
Tue Feb 3 09:20:20 CET 2009


Maxim Treskin wrote:
> Hello
> 
> I found incomprehensible thing in dialyzer's output for MatchSpec using 
> records.
> 
> This is my module:
> =======================================
> -module(loc).
> -export([get_ctrl_good/1]).
> 
> -record(controller, {
>           id :: integer(),
>           address :: any(),
>           type :: any(),
>           name :: string(),
>           profile :: integer()
>          }).
> 
> get_ctrl_good(CtrlId) ->
>     CtrlMS = [{#controller{id = CtrlId, _='_'}, [], ['$_']}],
>     case mnesia:dirty_select(controller, CtrlMS) of
>         [Controller] -> [Controller];
>         _ -> not_found
>     end.
> =======================================
> 
> So, when I make dialyzer --src -c loc.erl, I see following output:
> 
>  >>>>>>>
>   Checking whether the PLT /home/zert/.dialyzer_plt is up-to-date... yes
>   Proceeding with analysis...
> loc.erl:13: Function get_ctrl_good/1 has no local return
> loc.erl:14: Record construction 
> #controller{id::any(),address::'_',type::'_',name::'_',profile::'_'} 
> violates the declared type for #controller{}
>  done in 0m0.59s
> done (warnings were emitted)
>  >>>>>>>
> 
> get_ctrl_good/1 works fine, but dialyzer not think so.

The problem is that Dialyzer is agnostic about the language of match 
specs, which looks like Erlang but in reality is a totally different 
language.

What happens here is that you declared some record fields (e.g. profile) 
to contain integers only and then, as far as *Erlang* is concerned, your 
code contains a record construction where these fields get a value which 
  is an atom, not an integer.

I am not so convinced that Dialyzer is to blame here...  I think that 
having match specs expand to code with Erlang syntax but not Erlang 
semantics is a bad design choice and perhaps it should be revised.  We 
will discuss this with the OTP folks and see what can be done about it.


In the meantime, you can bypass this particular problem by allowing all 
record fields that need it to include the atom '_' in their set of 
allowed types.  I.e. change the record specification to:

-record(controller, {
           id :: integer(),
           address :: any(),
           type :: any(),
           name :: string() | '_',
           profile :: integer() | '_'
          }).

Definitely not pretty, but it will do the trick.

Kostis



More information about the erlang-questions mailing list