Dialyzer warning on pattern match with sub-record

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Dialyzer warning on pattern match with sub-record

Russell Brown-3
Hi,

I have a dialyzer error I can’t figure out, at all, it’s truly very weird, even for dialyzer.

The error is:

riak_kv_vnode.erl:2695: Matching of pattern State = {'state', _, _, _, _, _, VId, _, _, _, _, _, _, _, _, _, _, _, _, _, {'counter_state', 'false', _, _, _, _}, _, _} tagged with a record name violates the declared type of #state{idx::'undefined' | integer(),mod::atom() | tuple(),async_put::'false' | 'true' | 'undefined',vnodeid::'undefined' | binary(),delete_mode::'immediate' | 'keep' | 'undefined' | pos_integer(),bucket_buf_size::'undefined' | pos_integer(),index_buf_size::'undefined' | pos_integer(),key_buf_size::'undefined' | pos_integer(),async_folding::'false' | 'true' | 'undefined',in_handoff::boolean(),handoff_target::atom(),handoffs_rejected::integer(),forward::atom() | [{integer(),atom()}],hashtrees::'undefined' | pid(),upgrade_hashtree::boolean(),md_cache::atom() | tid(),md_cache_size::'undefined' | pos_integer(),counter::'undefined' | #counter_state{use::'true',cnt::non_neg_integer(),lease::non_neg_integer(),lease_size::non_neg_integer(),leasing::boolean()},status_mgr_pid::'undefined' | pid(),update_hook::atom() | tuple()}
  riak_object:object/0


The code in question is:

%% @private generate an epoch actor, and update the vnode state.
-spec new_key_epoch(#state{}) -> {NewEpoch::boolean(), EpochActor :: binary(), #state{}}.
new_key_epoch(State=#state{vnodeid=VId, counter=#counter_state{use=false}}) ->
    {false, VId, State};
new_key_epoch(State) ->
    NewState=#state{counter=#counter_state{cnt=Cntr}, vnodeid=VId} = update_counter(State),
    EpochId = key_epoch_actor(VId, Cntr),
    {true, EpochId, NewState}.


What is really freaky (to me) is that this code (the previous version) does not provoke a dialyzer warning:

%% @private generate an epoch actor, and update the vnode state.
-spec new_key_epoch(#state{}) -> {EpochActor :: binary(), #state{}}.
new_key_epoch(State=#state{vnodeid=VId, counter=#counter_state{use=false}}) ->
    {VId, State};
new_key_epoch(State) ->
    NewState=#state{counter=#counter_state{cnt=Cntr}, vnodeid=VId} = update_counter(State),
    EpochId = key_epoch_actor(VId, Cntr),
    {EpochId, NewState}.

The record definition for #counter_state is:

-record(counter_state, {
          use = true :: boolean(),
          cnt = 0 :: non_neg_integer(),
          lease = 0 :: non_neg_integer(),
          lease_size = 0 :: non_neg_integer(),
          leasing = false :: boolean()
         }).

I have missed out the record definition for #state as it is huge, but crucially, unchanged between the two definitions of new_key_epoch/1 above.

If the match in the function head, and the record, are exactly the same between the two versions of the code, why does the one that returns a three tuple provoke a warning?

Many thanks in advance if you can help

Cheers

Russell

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Dialyzer warning on pattern match with sub-record

Alex S.
> #counter_state{use::'true',cnt::non_neg_integer(),lease::non_neg_integer(),lease_size::non_neg_integer(),leasing::boolean()}

Dialyzer somehow figured out that counter_state is never constructed with ‘false’ (and has no explicit contract).

> 30 марта 2017 г., в 10:04, Russell Brown <[hidden email]> написал(а):
>
> Hi,
>
> I have a dialyzer error I can’t figure out, at all, it’s truly very weird, even for dialyzer.
>
> The error is:
>
> riak_kv_vnode.erl:2695: Matching of pattern State = {'state', _, _, _, _, _, VId, _, _, _, _, _, _, _, _, _, _, _, _, _, {'counter_state', 'false', _, _, _, _}, _, _} tagged with a record name violates the declared type of #state{idx::'undefined' | integer(),mod::atom() | tuple(),async_put::'false' | 'true' | 'undefined',vnodeid::'undefined' | binary(),delete_mode::'immediate' | 'keep' | 'undefined' | pos_integer(),bucket_buf_size::'undefined' | pos_integer(),index_buf_size::'undefined' | pos_integer(),key_buf_size::'undefined' | pos_integer(),async_folding::'false' | 'true' | 'undefined',in_handoff::boolean(),handoff_target::atom(),handoffs_rejected::integer(),forward::atom() | [{integer(),atom()}],hashtrees::'undefined' | pid(),upgrade_hashtree::boolean(),md_cache::atom() | tid(),md_cache_size::'undefined' | pos_integer(),counter::'undefined' | #counter_state{use::'true',cnt::non_neg_integer(),lease::non_neg_integer(),lease_size::non_neg_integer(),leasing::boolean()},status_mgr_pid::'undefined' | pid(),update_hook::atom() | tuple()}
>  riak_object:object/0
>
>
> The code in question is:
>
> %% @private generate an epoch actor, and update the vnode state.
> -spec new_key_epoch(#state{}) -> {NewEpoch::boolean(), EpochActor :: binary(), #state{}}.
> new_key_epoch(State=#state{vnodeid=VId, counter=#counter_state{use=false}}) ->
>    {false, VId, State};
> new_key_epoch(State) ->
>    NewState=#state{counter=#counter_state{cnt=Cntr}, vnodeid=VId} = update_counter(State),
>    EpochId = key_epoch_actor(VId, Cntr),
>    {true, EpochId, NewState}.
>
>
> What is really freaky (to me) is that this code (the previous version) does not provoke a dialyzer warning:
>
> %% @private generate an epoch actor, and update the vnode state.
> -spec new_key_epoch(#state{}) -> {EpochActor :: binary(), #state{}}.
> new_key_epoch(State=#state{vnodeid=VId, counter=#counter_state{use=false}}) ->
>    {VId, State};
> new_key_epoch(State) ->
>    NewState=#state{counter=#counter_state{cnt=Cntr}, vnodeid=VId} = update_counter(State),
>    EpochId = key_epoch_actor(VId, Cntr),
>    {EpochId, NewState}.
>
> The record definition for #counter_state is:
>
> -record(counter_state, {
>          use = true :: boolean(),
>          cnt = 0 :: non_neg_integer(),
>          lease = 0 :: non_neg_integer(),
>          lease_size = 0 :: non_neg_integer(),
>          leasing = false :: boolean()
>         }).
>
> I have missed out the record definition for #state as it is huge, but crucially, unchanged between the two definitions of new_key_epoch/1 above.
>
> If the match in the function head, and the record, are exactly the same between the two versions of the code, why does the one that returns a three tuple provoke a warning?
>
> Many thanks in advance if you can help
>
> Cheers
>
> Russell
>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Dialyzer warning on pattern match with sub-record

Russell Brown-3

On 30 Mar 2017, at 09:00, Alex S. <[hidden email]> wrote:

>> #counter_state{use::'true',cnt::non_neg_integer(),lease::non_neg_integer(),lease_size::non_neg_integer(),leasing::boolean()}
>
> Dialyzer somehow figured out that counter_state is never constructed with ‘false’ (and has no explicit contract).

Thanks for the reply, there is a code path where counter state can be updated to have `use=false`. I’m sorry but I don’t know what “no explicit contract” means in this context, can you explain?

Do you know how changing the return type tipped dialyzer off?

>> 30 марта 2017 г., в 10:04, Russell Brown <[hidden email]> написал(а):
>>
>> Hi,
>>
>> I have a dialyzer error I can’t figure out, at all, it’s truly very weird, even for dialyzer.
>>
>> The error is:
>>
>> riak_kv_vnode.erl:2695: Matching of pattern State = {'state', _, _, _, _, _, VId, _, _, _, _, _, _, _, _, _, _, _, _, _, {'counter_state', 'false', _, _, _, _}, _, _} tagged with a record name violates the declared type of #state{idx::'undefined' | integer(),mod::atom() | tuple(),async_put::'false' | 'true' | 'undefined',vnodeid::'undefined' | binary(),delete_mode::'immediate' | 'keep' | 'undefined' | pos_integer(),bucket_buf_size::'undefined' | pos_integer(),index_buf_size::'undefined' | pos_integer(),key_buf_size::'undefined' | pos_integer(),async_folding::'false' | 'true' | 'undefined',in_handoff::boolean(),handoff_target::atom(),handoffs_rejected::integer(),forward::atom() | [{integer(),atom()}],hashtrees::'undefined' | pid(),upgrade_hashtree::boolean(),md_cache::atom() | tid(),md_cache_size::'undefined' | pos_integer(),counter::'undefined' | #counter_state{use::'true',cnt::non_neg_integer(),lease::non_neg_integer(),lease_size::non_neg_integer(),leasing::boolean()},status_mgr_pid::'undefined' | pid(),update_hook::atom() | tuple()}
>> riak_object:object/0
>>
>>
>> The code in question is:
>>
>> %% @private generate an epoch actor, and update the vnode state.
>> -spec new_key_epoch(#state{}) -> {NewEpoch::boolean(), EpochActor :: binary(), #state{}}.
>> new_key_epoch(State=#state{vnodeid=VId, counter=#counter_state{use=false}}) ->
>>   {false, VId, State};
>> new_key_epoch(State) ->
>>   NewState=#state{counter=#counter_state{cnt=Cntr}, vnodeid=VId} = update_counter(State),
>>   EpochId = key_epoch_actor(VId, Cntr),
>>   {true, EpochId, NewState}.
>>
>>
>> What is really freaky (to me) is that this code (the previous version) does not provoke a dialyzer warning:
>>
>> %% @private generate an epoch actor, and update the vnode state.
>> -spec new_key_epoch(#state{}) -> {EpochActor :: binary(), #state{}}.
>> new_key_epoch(State=#state{vnodeid=VId, counter=#counter_state{use=false}}) ->
>>   {VId, State};
>> new_key_epoch(State) ->
>>   NewState=#state{counter=#counter_state{cnt=Cntr}, vnodeid=VId} = update_counter(State),
>>   EpochId = key_epoch_actor(VId, Cntr),
>>   {EpochId, NewState}.
>>
>> The record definition for #counter_state is:
>>
>> -record(counter_state, {
>>         use = true :: boolean(),
>>         cnt = 0 :: non_neg_integer(),
>>         lease = 0 :: non_neg_integer(),
>>         lease_size = 0 :: non_neg_integer(),
>>         leasing = false :: boolean()
>>        }).
>>
>> I have missed out the record definition for #state as it is huge, but crucially, unchanged between the two definitions of new_key_epoch/1 above.
>>
>> If the match in the function head, and the record, are exactly the same between the two versions of the code, why does the one that returns a three tuple provoke a warning?
>>
>> Many thanks in advance if you can help
>>
>> Cheers
>>
>> Russell
>>
>> _______________________________________________
>> erlang-questions mailing list
>> [hidden email]
>> http://erlang.org/mailman/listinfo/erlang-questions
>

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Dialyzer warning on pattern match with sub-record

Alex S.

> 30 марта 2017 г., в 11:06, Russell Brown <[hidden email]> написал(а):
>
>
> On 30 Mar 2017, at 09:00, Alex S. <[hidden email]> wrote:
>
>>> #counter_state{use::'true',cnt::non_neg_integer(),lease::non_neg_integer(),lease_size::non_neg_integer(),leasing::boolean()}
>>
>> Dialyzer somehow figured out that counter_state is never constructed with ‘false’ (and has no explicit contract).
>
> Thanks for the reply, there is a code path where counter state can be updated to have `use=false`. I’m sorry but I don’t know what “no explicit contract” means in this context, can you explain?
>
> Do you know how changing the return type tipped dialyzer off?

That means dialyzer figured out that this code path is never executed successfully, and contains a typing error. It is not a mistake to have a dead code, according to Dialyzer, just having all code dead in a function.

Explicit contract means declaring types for counter_state, though maybe it is ignored for local records.

Changing the return type might’ve broken the exact code path that can change ‘use’ to ‘false’.

>
>>> 30 марта 2017 г., в 10:04, Russell Brown <[hidden email]> написал(а):
>>>
>>> Hi,
>>>
>>> I have a dialyzer error I can’t figure out, at all, it’s truly very weird, even for dialyzer.
>>>
>>> The error is:
>>>
>>> riak_kv_vnode.erl:2695: Matching of pattern State = {'state', _, _, _, _, _, VId, _, _, _, _, _, _, _, _, _, _, _, _, _, {'counter_state', 'false', _, _, _, _}, _, _} tagged with a record name violates the declared type of #state{idx::'undefined' | integer(),mod::atom() | tuple(),async_put::'false' | 'true' | 'undefined',vnodeid::'undefined' | binary(),delete_mode::'immediate' | 'keep' | 'undefined' | pos_integer(),bucket_buf_size::'undefined' | pos_integer(),index_buf_size::'undefined' | pos_integer(),key_buf_size::'undefined' | pos_integer(),async_folding::'false' | 'true' | 'undefined',in_handoff::boolean(),handoff_target::atom(),handoffs_rejected::integer(),forward::atom() | [{integer(),atom()}],hashtrees::'undefined' | pid(),upgrade_hashtree::boolean(),md_cache::atom() | tid(),md_cache_size::'undefined' | pos_integer(),counter::'undefined' | #counter_state{use::'true',cnt::non_neg_integer(),lease::non_neg_integer(),lease_size::non_neg_integer(),leasing::boolean()},status_mgr_pid::'undefined' | pid(),update_hook::atom() | tuple()}
>>> riak_object:object/0
>>>
>>>
>>> The code in question is:
>>>
>>> %% @private generate an epoch actor, and update the vnode state.
>>> -spec new_key_epoch(#state{}) -> {NewEpoch::boolean(), EpochActor :: binary(), #state{}}.
>>> new_key_epoch(State=#state{vnodeid=VId, counter=#counter_state{use=false}}) ->
>>>  {false, VId, State};
>>> new_key_epoch(State) ->
>>>  NewState=#state{counter=#counter_state{cnt=Cntr}, vnodeid=VId} = update_counter(State),
>>>  EpochId = key_epoch_actor(VId, Cntr),
>>>  {true, EpochId, NewState}.
>>>
>>>
>>> What is really freaky (to me) is that this code (the previous version) does not provoke a dialyzer warning:
>>>
>>> %% @private generate an epoch actor, and update the vnode state.
>>> -spec new_key_epoch(#state{}) -> {EpochActor :: binary(), #state{}}.
>>> new_key_epoch(State=#state{vnodeid=VId, counter=#counter_state{use=false}}) ->
>>>  {VId, State};
>>> new_key_epoch(State) ->
>>>  NewState=#state{counter=#counter_state{cnt=Cntr}, vnodeid=VId} = update_counter(State),
>>>  EpochId = key_epoch_actor(VId, Cntr),
>>>  {EpochId, NewState}.
>>>
>>> The record definition for #counter_state is:
>>>
>>> -record(counter_state, {
>>>        use = true :: boolean(),
>>>        cnt = 0 :: non_neg_integer(),
>>>        lease = 0 :: non_neg_integer(),
>>>        lease_size = 0 :: non_neg_integer(),
>>>        leasing = false :: boolean()
>>>       }).
>>>
>>> I have missed out the record definition for #state as it is huge, but crucially, unchanged between the two definitions of new_key_epoch/1 above.
>>>
>>> If the match in the function head, and the record, are exactly the same between the two versions of the code, why does the one that returns a three tuple provoke a warning?
>>>
>>> Many thanks in advance if you can help
>>>
>>> Cheers
>>>
>>> Russell
>>>
>>> _______________________________________________
>>> erlang-questions mailing list
>>> [hidden email]
>>> http://erlang.org/mailman/listinfo/erlang-questions
>>
>

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Dialyzer warning on pattern match with sub-record

Russell Brown-3

On 30 Mar 2017, at 09:08, Alex S. <[hidden email]> wrote:

>>
>> 30 марта 2017 г., в 11:06, Russell Brown <[hidden email]> написал(а):
>>
>>
>> On 30 Mar 2017, at 09:00, Alex S. <[hidden email]> wrote:
>>
>>>> #counter_state{use::'true',cnt::non_neg_integer(),lease::non_neg_integer(),lease_size::non_neg_integer(),leasing::boolean()}
>>>
>>> Dialyzer somehow figured out that counter_state is never constructed with ‘false’ (and has no explicit contract).
>>
>> Thanks for the reply, there is a code path where counter state can be updated to have `use=false`. I’m sorry but I don’t know what “no explicit contract” means in this context, can you explain?
>>
>> Do you know how changing the return type tipped dialyzer off?
>
> That means dialyzer figured out that this code path is never executed successfully, and contains a typing error. It is not a mistake to have a dead code, according to Dialyzer, just having all code dead in a function.
>
> Explicit contract means declaring types for counter_state, though maybe it is ignored for local records.
>
> Changing the return type might’ve broken the exact code path that can change ‘use’ to ‘false’.

I checked, it does not. This is very confusing. I can quite easily call the function with use=false, by changing a setting in riak’s advanced.config. Is the fact that this value comes from an app variable the problem?

>
>>
>>>> 30 марта 2017 г., в 10:04, Russell Brown <[hidden email]> написал(а):
>>>>
>>>> Hi,
>>>>
>>>> I have a dialyzer error I can’t figure out, at all, it’s truly very weird, even for dialyzer.
>>>>
>>>> The error is:
>>>>
>>>> riak_kv_vnode.erl:2695: Matching of pattern State = {'state', _, _, _, _, _, VId, _, _, _, _, _, _, _, _, _, _, _, _, _, {'counter_state', 'false', _, _, _, _}, _, _} tagged with a record name violates the declared type of #state{idx::'undefined' | integer(),mod::atom() | tuple(),async_put::'false' | 'true' | 'undefined',vnodeid::'undefined' | binary(),delete_mode::'immediate' | 'keep' | 'undefined' | pos_integer(),bucket_buf_size::'undefined' | pos_integer(),index_buf_size::'undefined' | pos_integer(),key_buf_size::'undefined' | pos_integer(),async_folding::'false' | 'true' | 'undefined',in_handoff::boolean(),handoff_target::atom(),handoffs_rejected::integer(),forward::atom() | [{integer(),atom()}],hashtrees::'undefined' | pid(),upgrade_hashtree::boolean(),md_cache::atom() | tid(),md_cache_size::'undefined' | pos_integer(),counter::'undefined' | #counter_state{use::'true',cnt::non_neg_integer(),lease::non_neg_integer(),lease_size::non_neg_integer(),leasing::boolean()},status_mgr_pid::'undefined' | pid(),update_hook::atom() | tuple()}
>>>> riak_object:object/0
>>>>
>>>>
>>>> The code in question is:
>>>>
>>>> %% @private generate an epoch actor, and update the vnode state.
>>>> -spec new_key_epoch(#state{}) -> {NewEpoch::boolean(), EpochActor :: binary(), #state{}}.
>>>> new_key_epoch(State=#state{vnodeid=VId, counter=#counter_state{use=false}}) ->
>>>> {false, VId, State};
>>>> new_key_epoch(State) ->
>>>> NewState=#state{counter=#counter_state{cnt=Cntr}, vnodeid=VId} = update_counter(State),
>>>> EpochId = key_epoch_actor(VId, Cntr),
>>>> {true, EpochId, NewState}.
>>>>
>>>>
>>>> What is really freaky (to me) is that this code (the previous version) does not provoke a dialyzer warning:
>>>>
>>>> %% @private generate an epoch actor, and update the vnode state.
>>>> -spec new_key_epoch(#state{}) -> {EpochActor :: binary(), #state{}}.
>>>> new_key_epoch(State=#state{vnodeid=VId, counter=#counter_state{use=false}}) ->
>>>> {VId, State};
>>>> new_key_epoch(State) ->
>>>> NewState=#state{counter=#counter_state{cnt=Cntr}, vnodeid=VId} = update_counter(State),
>>>> EpochId = key_epoch_actor(VId, Cntr),
>>>> {EpochId, NewState}.
>>>>
>>>> The record definition for #counter_state is:
>>>>
>>>> -record(counter_state, {
>>>>       use = true :: boolean(),
>>>>       cnt = 0 :: non_neg_integer(),
>>>>       lease = 0 :: non_neg_integer(),
>>>>       lease_size = 0 :: non_neg_integer(),
>>>>       leasing = false :: boolean()
>>>>      }).
>>>>
>>>> I have missed out the record definition for #state as it is huge, but crucially, unchanged between the two definitions of new_key_epoch/1 above.
>>>>
>>>> If the match in the function head, and the record, are exactly the same between the two versions of the code, why does the one that returns a three tuple provoke a warning?
>>>>
>>>> Many thanks in advance if you can help
>>>>
>>>> Cheers
>>>>
>>>> Russell
>>>>
>>>> _______________________________________________
>>>> erlang-questions mailing list
>>>> [hidden email]
>>>> http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Dialyzer warning on pattern match with sub-record

Stavros Aronis
In reply to this post by Russell Brown-3
Hi Russell,

From your original warning:

On Thu, Mar 30, 2017 at 9:04 AM, Russell Brown <[hidden email]> wrote:
riak_kv_vnode.erl:2695: Matching of pattern State = {'state', _, _, _, _, _, VId, _, _, _, _, _, _, _, _, _, _, _, _, _, {'counter_state', 'false', _, _, _, _}, _, _} tagged with a record name violates the declared type of #state{idx::'undefined' | integer(),mod::atom() | tuple(),async_put::'false' | 'true' | 'undefined',vnodeid::'undefined' | binary(),delete_mode::'immediate' | 'keep' | 'undefined' | pos_integer(),bucket_buf_size::'undefined' | pos_integer(),index_buf_size::'undefined' | pos_integer(),key_buf_size::'undefined' | pos_integer(),async_folding::'false' | 'true' | 'undefined',in_handoff::boolean(),handoff_target::atom(),handoffs_rejected::integer(),forward::atom() | [{integer(),atom()}],hashtrees::'undefined' | pid(),upgrade_hashtree::boolean(),md_cache::atom() | tid(),md_cache_size::'undefined' | pos_integer(),counter::'undefined' | #counter_state{use::'true',cnt::non_neg_integer(),lease::non_neg_integer(),lease_size::non_neg_integer(),leasing::boolean()},status_mgr_pid::'undefined' | pid(),update_hook::atom() | tuple()}
  riak_object:object/0

my guess would be that in the definition of the #state record, the annotated #state.counter field's type is a #counter_state record whose #counter_state.use field annotated type is just the atom 'true'.

Can you send some context from that part of the module? (e.g. definition of #state and #counter_state records)

Best,

Stavros

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Dialyzer warning on pattern match with sub-record

Russell Brown-3
Hi Stavros,
Thanks for the reply.


On 30 Mar 2017, at 09:53, Stavros Aronis <[hidden email]> wrote:

> Hi Russell,
>
> From your original warning:
>
> On Thu, Mar 30, 2017 at 9:04 AM, Russell Brown <[hidden email]> wrote:
> riak_kv_vnode.erl:2695: Matching of pattern State = {'state', _, _, _, _, _, VId, _, _, _, _, _, _, _, _, _, _, _, _, _, {'counter_state', 'false', _, _, _, _}, _, _} tagged with a record name violates the declared type of #state{idx::'undefined' | integer(),mod::atom() | tuple(),async_put::'false' | 'true' | 'undefined',vnodeid::'undefined' | binary(),delete_mode::'immediate' | 'keep' | 'undefined' | pos_integer(),bucket_buf_size::'undefined' | pos_integer(),index_buf_size::'undefined' | pos_integer(),key_buf_size::'undefined' | pos_integer(),async_folding::'false' | 'true' | 'undefined',in_handoff::boolean(),handoff_target::atom(),handoffs_rejected::integer(),forward::atom() | [{integer(),atom()}],hashtrees::'undefined' | pid(),upgrade_hashtree::boolean(),md_cache::atom() | tid(),md_cache_size::'undefined' | pos_integer(),counter::'undefined' | #counter_state{use::'true',cnt::non_neg_integer(),lease::non_neg_integer(),lease_size::non_neg_integer(),leasing::boolean()},status_mgr_pid::'undefined' | pid(),update_hook::atom() | tuple()}
>   riak_object:object/0
>
> my guess would be that in the definition of the #state record, the annotated #state.counter field's type is a #counter_state record whose #counter_state.use field annotated type is just the atom 'true'.
>
> Can you send some context from that part of the module? (e.g. definition of #state and #counter_state records)

The record definition for #counter_state is:

-record(counter_state, {
         use = true :: boolean(),
         cnt = 0 :: non_neg_integer(),
         lease = 0 :: non_neg_integer(),
         lease_size = 0 :: non_neg_integer(),
         leasing = false :: boolean()
        }).

The #state record:
-record(state, {idx :: partition(),
                mod :: module(),
                async_put :: boolean(),
                modstate :: term(),
                mrjobs :: term(),
                vnodeid :: undefined | binary(),
                delete_mode :: keep | immediate | pos_integer(),
                bucket_buf_size :: pos_integer(),
                index_buf_size :: pos_integer(),
                key_buf_size :: pos_integer(),
                async_folding :: boolean(),
                in_handoff = false :: boolean(),
                handoff_target :: node(),
                handoffs_rejected = 0 :: integer(),
                forward :: node() | [{integer(), node()}],
                hashtrees :: pid(),
                upgrade_hashtree = false :: boolean(),
                md_cache :: ets:tab(),
                md_cache_size :: pos_integer(),
                counter :: #counter_state{},
                status_mgr_pid :: pid(), %% a process that manages vnode status persistence
                update_hook = riak_kv_noop_update_hook :: update_hook()
               }).

What I’m _most_ confused about is how the change of return type for that function surfaced this dialyzer warning.

Thanks again for your time

Russell

>
> Best,
>
> Stavros

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Dialyzer warning on pattern match with sub-record

Alex S.
In reply to this post by Russell Brown-3

30 марта 2017 г., в 11:12, Russell Brown <[hidden email]> написал(а):


On 30 Mar 2017, at 09:08, Alex S. <[hidden email]> wrote:


30 марта 2017 г., в 11:06, Russell Brown <[hidden email]> написал(а):


On 30 Mar 2017, at 09:00, Alex S. <[hidden email]> wrote:

#counter_state{use::'true',cnt::non_neg_integer(),lease::non_neg_integer(),lease_size::non_neg_integer(),leasing::boolean()}

Dialyzer somehow figured out that counter_state is never constructed with ‘false’ (and has no explicit contract).

Thanks for the reply, there is a code path where counter state can be updated to have `use=false`. I’m sorry but I don’t know what “no explicit contract” means in this context, can you explain?

Do you know how changing the return type tipped dialyzer off?

That means dialyzer figured out that this code path is never executed successfully, and contains a typing error. It is not a mistake to have a dead code, according to Dialyzer, just having all code dead in a function.

Explicit contract means declaring types for counter_state, though maybe it is ignored for local records.

Changing the return type might’ve broken the exact code path that can change ‘use’ to ‘false’.

I checked, it does not. This is very confusing. I can quite easily call the function with use=false, by changing a setting in riak’s advanced.config. Is the fact that this value comes from an app variable the problem?

So, it executed correctly with use=false, without errors, and dialyzer still reports it? Then that is a bug. Dialyzer should never report bugs in working code.




30 марта 2017 г., в 10:04, Russell Brown <[hidden email]> написал(а):

Hi,

I have a dialyzer error I can’t figure out, at all, it’s truly very weird, even for dialyzer.

The error is: 

riak_kv_vnode.erl:2695: Matching of pattern State = {'state', _, _, _, _, _, VId, _, _, _, _, _, _, _, _, _, _, _, _, _, {'counter_state', 'false', _, _, _, _}, _, _} tagged with a record name violates the declared type of #state{idx::'undefined' | integer(),mod::atom() | tuple(),async_put::'false' | 'true' | 'undefined',vnodeid::'undefined' | binary(),delete_mode::'immediate' | 'keep' | 'undefined' | pos_integer(),bucket_buf_size::'undefined' | pos_integer(),index_buf_size::'undefined' | pos_integer(),key_buf_size::'undefined' | pos_integer(),async_folding::'false' | 'true' | 'undefined',in_handoff::boolean(),handoff_target::atom(),handoffs_rejected::integer(),forward::atom() | [{integer(),atom()}],hashtrees::'undefined' | pid(),upgrade_hashtree::boolean(),md_cache::atom() | tid(),md_cache_size::'undefined' | pos_integer(),counter::'undefined' | #counter_state{use::'true',cnt::non_neg_integer(),lease::non_neg_integer(),lease_size::non_neg_integer(),leasing::boolean()},status_mgr_pid::'undefined' | pid(),update_hook::atom() | tuple()}
riak_object:object/0


The code in question is:

%% @private generate an epoch actor, and update the vnode state.
-spec new_key_epoch(#state{}) -> {NewEpoch::boolean(), EpochActor :: binary(), #state{}}.
new_key_epoch(State=#state{vnodeid=VId, counter=#counter_state{use=false}}) ->
{false, VId, State};
new_key_epoch(State) ->
NewState=#state{counter=#counter_state{cnt=Cntr}, vnodeid=VId} = update_counter(State),
EpochId = key_epoch_actor(VId, Cntr),
{true, EpochId, NewState}.


What is really freaky (to me) is that this code (the previous version) does not provoke a dialyzer warning:

%% @private generate an epoch actor, and update the vnode state.
-spec new_key_epoch(#state{}) -> {EpochActor :: binary(), #state{}}.
new_key_epoch(State=#state{vnodeid=VId, counter=#counter_state{use=false}}) ->
{VId, State};
new_key_epoch(State) ->
NewState=#state{counter=#counter_state{cnt=Cntr}, vnodeid=VId} = update_counter(State),
EpochId = key_epoch_actor(VId, Cntr),
{EpochId, NewState}.

The record definition for #counter_state is:

-record(counter_state, {
     use = true :: boolean(),
     cnt = 0 :: non_neg_integer(),
     lease = 0 :: non_neg_integer(),
     lease_size = 0 :: non_neg_integer(),
     leasing = false :: boolean()
    }).

I have missed out the record definition for #state as it is huge, but crucially, unchanged between the two definitions of new_key_epoch/1 above.

If the match in the function head, and the record, are exactly the same between the two versions of the code, why does the one that returns a three tuple provoke a warning?

Many thanks in advance if you can help

Cheers

Russell

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Dialyzer warning on pattern match with sub-record

Russell Brown-3

On 30 Mar 2017, at 15:26, Alex S. <[hidden email]> wrote:

>>
>> 30 марта 2017 г., в 11:12, Russell Brown <[hidden email]> написал(а):
>>
>>
>> On 30 Mar 2017, at 09:08, Alex S. <[hidden email]> wrote:
>>
>>>>
>>
>> I checked, it does not. This is very confusing. I can quite easily call the function with use=false, by changing a setting in riak’s advanced.config. Is the fact that this value comes from an app variable the problem?
>
> So, it executed correctly with use=false, without errors, and dialyzer still reports it? Then that is a bug. Dialyzer should never report bugs in working code.

Current thinking from the reviewer (Doug Rohrer, I know he’s on this list!) is that this head/match is now redundant, since the functions that call it check for use=true before calling new_key_epoch. So dialzyer is correct, the function only ever gets called with `true` now. Once again the age old refrain “never argue with dialyzer”. I hope that someone learned something so this thread wasn’t a complete waste of time.

Thanks, and thanks to all who replied.

Cheers

Russell

>
>>
>>>>>>
>>>>>> Russell
>>>>>>
>>>>>> _______________________________________________
>>>>>> erlang-questions mailing list
>>>>>> [hidden email]
>>>>>> http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Loading...