Re: Dialyzer warning when returning a prolist

Paulo Zulato <[email protected]>
Newsgroups gmane.comp.lang.erlang.general
Message-ID <CAATrJfcN9wfN3OPi32dNvKVcK7JNM0C5BYDD1pChyRCbT_q4kA@mail.gmail.com>
Hi, Fred and Stanislav,

Thank you for your replies.
Now I understood why dialyzer is complaining about the underspec return. It
really makes sense.
But I still didn't get why proplists is "working". I've enabled the
*unknown* warning as stated below and I'm using OTP24 and the latest
rebar3. The behaviour is the same with or without the *unknown* warning:

rebar.config:

> {erl_opts, [debug_info]}.
> {deps, []}.
> {dialyzer, [
>    {get_warnings, true},
>    {warnings, [error_handling, underspecs, *unknown*, unmatched_returns]}
> ]}.
>

Source with proplist emulation:

> -module(test).
>
> -export([test/0]).
>
> %% From <https://erlang.org/doc/man/proplists.html>
> -type property() :: atom() | tuple().
> -type proplist() :: [property()].
> -spec test() -> proplist().
> test() ->
>    [
>        {one_test, [a,b,c]},
>        {another_test, [d,e,f]}
>    ].
>

Result:

> ===> Verifying dependencies...
> ===> Analyzing applications...
> ===> Compiling test
> ===> Dialyzer starting, this may take a while...
> ===> Updating plt...
> ===> Resolving files...
> ===> Updating base plt...
> ===> Resolving files...
> ===> Checking 204 files in
> ../../home/pzulato/.cache/rebar3/rebar3_24.0_plt...
> ===> Copying ../../home/pzulato/.cache/rebar3/rebar3_24.0_plt to
> _build/default/rebar3_24.0_plt...
> ===> Checking 204 files in _build/default/rebar3_24.0_plt...
> ===> Doing success typing analysis...
> ===> Resolving files...
> ===> Analyzing 1 files with _build/default/rebar3_24.0_plt...
>
> src/test.erl
> Line 8 Column 2: Type specification test:test() -> proplist() is a
> supertype of the success typing: test:test() -> [{'another_test',['d' |
> 'e' | 'f',...]} | {'one_test',['a' | 'b' | 'c',...]},...]
> ===> Warnings written to _build/default/24.0.dialyzer_warnings
> ===> Warnings occurred running dialyzer: 1
>

Source with real proplist:

> -module(test).
>
> -export([test/0]).
>
> -spec test() -> proplists:proplist().
> test() ->
>    [
>        {one_test, [a,b,c]},
>        {another_test, [d,e,f]}
>    ].
>

Result:

> ===> Verifying dependencies...
> ===> Analyzing applications...
> ===> Compiling test
> ===> Dialyzer starting, this may take a while...
> ===> Updating plt...
> ===> Resolving files...
> ===> Checking 204 files in _build/default/rebar3_24.0_plt...
> ===> Doing success typing analysis...
> ===> Resolving files...
> ===> Analyzing 1 files with _build/default/rebar3_24.0_plt...
>


Do I need to do something else than adding the *unknown* warning into
rebar.config or is it enough?


Best regards,
Paulo Zulato

--
«Quis custodiet ipsos custodes?»


On Tue, 18 May 2021 at 03:50, Stanislav Ledenev <[email protected]> wrote:

> 1. As I understand underspec and overspec requires precise indication of
> types.
> So for a list of a,b,c atoms you _must_ indicate [a,b,c] but not just a
> list of atoms.
> Because list of atoms implies a list of any size with any atoms not a list
> of 3 specific atoms a,b,c.
>
> 2. The only possible reason why proplists:proplist "works" is that the
> dialyzer
> doesn't know about this type and it is kinda silent in such cases. Try
> -Wunknown option.
>
> пн, 17 мая 2021 г. в 23:25, Paulo Zulato <[email protected]>:
>
>> Hello,
>>
>> I'm trying to figure out why dialyzer is complaining about a function
>> when I don't explicitly declare its return as a proplist.
>> I have this small module which returns a proplist in the form {atom(),
>> [atom()]}:
>>
>>> -module(test).
>>>
>>> -export([test/0]).
>>> test() ->
>>>    [
>>>        {one_test, [a,b,c]},
>>>        {another_test, [d,e,f]}
>>>    ].
>>>
>>
>> For function above, I made the following spec, but dialyzer has
>> complained (as stated below) when I enabled its underspecs warnings.
>>
>>> -spec test() -> [{atom(), [atom()]}].
>>> % src/test.erl
>>> %    Type specification test:test() -> [{atom(),[atom()]}] is a
>>> supertype of the success typing: test:test() -> [{'another_test',['d' | 'e'
>>> | 'f',...]} | {'one_test',['a' | 'b' | 'c',...]},...]
>>>
>>
>> Well... both lists are non-empty lists as stated by dialyzer, so I
>> modified the spec, without success:
>>
>>> -spec test() -> [{atom(), [atom(), ...]}, ...].
>>> %src/test.erl
>>> %   Type specification test:test() -> [{atom(),[atom(),...]},...] is a
>>> supertype of the success typing: test:test() -> [{'another_test',['d' | 'e'
>>> | 'f',...]} | {'one_test',['a' | 'b' | 'c',...]},...]
>>>
>>
>> Then I tried to explicitly declare it as a proplist, and dialyzer has
>> accepted it:
>>
>>> -spec test() -> proplists:proplist().
>>> % OK, no warnings.
>>>
>>
>> As it worked, I tried to do the same as proplists module does and created
>> two types, which I used on my new spec. And, surprisingly, dialyzer has
>> complained about it!
>>
>>> % From <https://erlang.org/doc/man/proplists.html>
>>> -type property() :: atom() | tuple().
>>> -type proplist() :: [property()].
>>>
>>
>>> -spec test() -> proplist().
>>> %src/test.erl
>>>
>> %   Type specification test:test() -> proplist() is a supertype of the
>>> success typing: test:test() -> [{'another_test',['d' | 'e' | 'f',...]} |
>>> {'one_test',['a' | 'b' | 'c',...]},...]
>>>
>>
>> Therefore, I could not understand why declaring the return as
>> "proplists:proplist" is OK while declaring it as lists, nonempty lists or
>> creating the same types as proplists are not OK. Why is dialyzer
>> complaining about the other specs? Is dialyzer handling proplists in a
>> different way? Could someone help me to understand this behaviour?
>>
>>
>> Best Regards,
>> Paulo Zulato
>>
>> --
>> «Quis custodiet ipsos custodes?»
>>
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.