[erlang-questions] Dialyzer warning on pattern match with sub-record

Alex S. alex0player@REDACTED
Thu Mar 30 16:26:43 CEST 2017


> 30 марта 2017 г., в 11:12, Russell Brown <russell@REDACTED> написал(а):
> 
> 
> On 30 Mar 2017, at 09:08, Alex S. <alex0player@REDACTED <mailto:alex0player@REDACTED>> wrote:
> 
>>> 
>>> 30 марта 2017 г., в 11:06, Russell Brown <russell@REDACTED> написал(а):
>>> 
>>> 
>>> On 30 Mar 2017, at 09:00, Alex S. <alex0player@REDACTED> 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 <russell@REDACTED> написал(а):
>>>>> 
>>>>> 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
>>>>> erlang-questions@REDACTED
>>>>> http://erlang.org/mailman/listinfo/erlang-questions

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20170330/2b236ffd/attachment.htm>


More information about the erlang-questions mailing list