<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Hi Raghav,</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>I have a private gig at my company: I dialyze projects for beer (true story).</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>Let me show you an example of my mental process based on your commit. Let’s tackle like 197…</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>It reads:</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>_ = bitcask_fileops:close_for_writing(WriteFile),</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>And dialyzer is saying that the call to that function will never return since <b class="">it differs</b> the first <i class="">(and only)</i> argument can’t be <b class="">fresh</b> nor <b class="">undefined</b>.</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>There are 3 possibilities here:</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>1. bitcask_fileops:close_for_writing/1 actually accepts other kinds of arguments, but the clauses where those types are accepted are also questioned by dialyzer so, in dialyzer’s eyes, they can never happen.</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>2. WriteFile can actually be <b class="">fresh</b> or <b class="">undefined</b>, but dialyzer is fooled by a misplaced spec somewhere.</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>3. The code is actually broken (i.e. bitcask_fileops:close_for_writing/1 expects fresh or undefined and WriteFile can never be any of those)</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>Let’s discard #3… I bet your app is tested with 100% coverage, so that can’t happen.</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>Let’s aim for #1. We have to check the bitcask_fileops:close_for_writing/1’s code. …and <b class="">bingo!</b> bitcask_fileops:close_for_writing/1 does have a third clause that, instead of <b class="">fresh</b> or <b class="">undefined</b> can receive a <b class="">#filestate{}</b> record (with some fixed params).</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>Dialyzer must have produced a warning for that one, too… for sure. We check your list and… we found no warning in these lines (236-238).</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>That’s bad, but check it out, that function is calling <b class="">close_hintfile/1</b> and we do have warnings for that one, specifically:</div><div class=""><br class=""></div><div class=""><div class=""> 240: Function close_hintfile/1 has no local return</div><div class=""> 240: Matching of pattern {'filestate', _, _, _, _, 'undefined', _, _, _, _, _} tagged with a record name violates the declared type of #filestate{mode::'read_only' | 'read_write' | 'undefined',filename::string(),tstamp::'undefined' | integer(),fd::'undefined' | port(),hintfd::port(),hintcrc::integer(),ofs::'undefined' | non_neg_integer(),l_ofs::non_neg_integer(),l_hbytes::non_neg_integer(),l_hintcrc::non_neg_integer()}</div><div class=""> 251: Record construction #filestate{mode::'read_only' | 'read_write' | 'undefined',filename::string(),tstamp::'undefined' | integer(),fd::'undefined' | port(),hintfd::'undefined',hintcrc::0,ofs::'undefined' | non_neg_integer(),l_ofs::non_neg_integer(),l_hbytes::non_neg_integer(),l_hintcrc::non_neg_integer()} violates the declared type of field hintfd::port()</div></div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>Ok, so the function has no local return, that explains all! (o_O)</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>Anyway, let’s check the last 2, shall we?</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>On line 240, header of the first clause of the function, we’re using <b class="">undefined</b> in a record field that doesn’t accept undefined. The warning can be improved, but it can be roughly translated in this way:</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>- Matching of pattern {‘filestate’, …} tagged with a record name… => The pattern with record filestate that you are using…</div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>- violates the declared type of #… => can never match an actual #filestate record because it’s using at least one sub-pattern that doesn’t match the type of the corresponding field. Here is the record definition:…</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>On line 251, where we’re building a filestate record, the warning is much clearer: Dialyzer says we’re using the wrong value for field <b class="">hintfd </b>which is defined as <b class="">port()</b>.</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>So, it’s pretty clear that our intention was to allow hintfd to be <b class="">undefined</b>.</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>My next step here would be to fix that (as you did) and run rebar3 dialyzer again.</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>We started from line 197… but we could’ve started this process from like 219 as well and reached the same conclusion, right?</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>I’m not sure if this is what you were actually looking for, but maybe it helps anyway.</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre"> </span>Happy dialyzing! :)</div><div class=""><br class=""></div><br class=""><div><blockquote type="cite" class=""><div class="">On Mar 2, 2017, at 06:39, Raghav Karol <<a href="mailto:raghav.karol@gmail.com" class="">raghav.karol@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class="">I spent a bit of time yesterday on some dialyzer warnings resulting from the singleton type 'undefined' no longer automatically to record fields types OTP-19. What threw me off were several related but hard to decipher warnings. </div><div class=""><br class=""></div><div class="">Using OTP-19, `rebar3 dialyzer` on this commit <a href="https://github.com/basho/bitcask/commit/cd74f59bfe47a39878d7a56a55ce0ae723723677" class="">https://github.com/basho/bitcask/commit/cd74f59bfe47a39878d7a56a55ce0ae723723677</a> produces: </div><div class=""><br class=""></div><div class="">```</div><div class="">src/bitcask.erl</div><div class=""> 197: The call bitcask_fileops:close_for_writing(WriteFile::#filestate{mode::'read_only' | 'read_write' | 'undefined',filename::string(),tstamp::'undefined' | integer(),fd::'undefined' | port(),hintfd::port(),hintcrc::integer(),ofs::'undefined' | non_neg_integer(),l_ofs::non_neg_integer(),l_hbytes::non_neg_integer(),l_hintcrc::non_neg_integer()}) will never return since it differs in the 1st argument from the success typing arguments: ('fresh' | 'undefined')</div><div class=""> 219: The call bitcask_fileops:close_for_writing(WriteFile::#filestate{mode::'read_only' | 'read_write' | 'undefined',filename::string(),tstamp::'undefined' | integer(),fd::'undefined' | port(),hintfd::port(),hintcrc::integer(),ofs::'undefined' | non_neg_integer(),l_ofs::non_neg_integer(),l_hbytes::non_neg_integer(),l_hintcrc::non_neg_integer()}) will never return since it differs in the 1st argument from the success typing arguments: ('fresh' | 'undefined')</div><div class=""> 520: The created fun has no local return</div><div class=""> 529: The call bitcask_fileops:close(FD::{_,_,_,_,_,_,_,_,_,_,_}) will never return since it differs in the 1st argument from the success typing arguments: ('fresh' | 'undefined')</div><div class=""> 717: The call bitcask_fileops:close(Outfile::#filestate{mode::'read_write',filename::string(),tstamp::'undefined' | integer(),fd::'undefined' | port(),hintfd::port(),hintcrc::integer(),ofs::'undefined' | non_neg_integer(),l_ofs::non_neg_integer(),l_hbytes::non_neg_integer(),l_hintcrc::non_neg_integer()}) will never return since it differs in the 1st argument from the success typing arguments: ('fresh' | 'undefined')</div><div class=""> 722: The call bitcask_fileops:close(TFile::#filestate{mode::'read_write',filename::string(),tstamp::'undefined' | integer(),fd::'undefined' | port(),hintfd::port(),hintcrc::integer(),ofs::'undefined' | non_neg_integer(),l_ofs::non_neg_integer(),l_hbytes::non_neg_integer(),l_hintcrc::non_neg_integer()}) will never return since it differs in the 1st argument from the success typing arguments: ('fresh' | 'undefined')</div><div class=""> 774: The call bitcask_fileops:close(F::#filestate{mode::'read_only' | 'read_write' | 'undefined',filename::[any()],tstamp::'undefined' | integer(),fd::'undefined' | port(),hintfd::port(),hintcrc::integer(),ofs::'undefined' | non_neg_integer(),l_ofs::non_neg_integer(),l_hbytes::non_neg_integer(),l_hintcrc::non_neg_integer()}) will never return since it differs in the 1st argument from the success typing arguments: ('fresh' | 'undefined')</div><div class="">1224: The call bitcask_fileops:close(File::#filestate{mode::'read_write',filename::string(),tstamp::integer(),fd::'undefined' | port(),hintfd::port(),hintcrc::non_neg_integer(),ofs::'undefined' | non_neg_integer(),l_ofs::0,l_hbytes::0,l_hintcrc::0}) will never return since it differs in the 1st argument from the success typing arguments: ('fresh' | 'undefined')</div><div class="">1719: The pattern <_Key, _Value, State, 0, LastErr> can never match the type <_,_,#bc_state{dirname::string(),write_file::'fresh' | 'undefined' | #filestate{mode::'read_only' | 'read_write' | 'undefined',filename::[any()],tstamp::'undefined' | integer(),fd::'undefined' | port(),hintfd::port(),hintcrc::integer(),ofs::'undefined' | non_neg_integer(),l_ofs::non_neg_integer(),l_hbytes::non_neg_integer(),l_hintcrc::non_neg_integer()},write_lock::'undefined' | reference(),read_files::'undefined' | [{_,_,_,_,_,_,_,_,_,_,_}],max_file_size::'undefined' | integer(),opts::'undefined' | [any()],key_transform::'undefined' | fun(),keydir::reference(),read_write_p::'undefined' | integer(),tombstone_version::0 | 2},100,'undefined'></div><div class="">1870: Function wrap_write_file/1 has no local return</div><div class="">1924: Record construction #filestate{filename::[any()],hintfd::'undefined',hintcrc::0,l_ofs::0,l_hbytes::0,l_hintcrc::0} violates the declared type of field hintfd::port()</div><div class=""><br class=""></div><div class="">src/bitcask_fileops.erl</div><div class=""> 166: Record construction #filestate{mode::'read_only',filename::string() | #filestate{mode::'read_only' | 'read_write' | 'undefined',filename::string(),tstamp::'undefined' | integer(),fd::'undefined' | port(),hintfd::port(),hintcrc::integer(),ofs::'undefined' | non_neg_integer(),l_ofs::non_neg_integer(),l_hbytes::non_neg_integer(),l_hintcrc::non_neg_integer()},tstamp::integer(),hintfd::'undefined',hintcrc::0,ofs::0,l_ofs::0,l_hbytes::0,l_hintcrc::0} violates the declared type of field hintfd::port()</div><div class=""> 240: Function close_hintfile/1 has no local return</div><div class=""> 240: Matching of pattern {'filestate', _, _, _, _, 'undefined', _, _, _, _, _} tagged with a record name violates the declared type of #filestate{mode::'read_only' | 'read_write' | 'undefined',filename::string(),tstamp::'undefined' | integer(),fd::'undefined' | port(),hintfd::port(),hintcrc::integer(),ofs::'undefined' | non_neg_integer(),l_ofs::non_neg_integer(),l_hbytes::non_neg_integer(),l_hintcrc::non_neg_integer()}</div><div class=""> 251: Record construction #filestate{mode::'read_only' | 'read_write' | 'undefined',filename::string(),tstamp::'undefined' | integer(),fd::'undefined' | port(),hintfd::'undefined',hintcrc::0,ofs::'undefined' | non_neg_integer(),l_ofs::non_neg_integer(),l_hbytes::non_neg_integer(),l_hintcrc::non_neg_integer()} violates the declared type of field hintfd::port()</div><div class=""> 314: The pattern 'undefined' can never match the type port()</div><div class=""><br class=""></div><div class="">src/bitcask_merge_delete.erl</div><div class=""> 151: Record construction #filestate{hintfd::'undefined',hintcrc::0,l_ofs::0,l_hbytes::0,l_hintcrc::0} violates the declared type of field hintfd::port()</div><div class="">===> Warnings written to /Users/raghav/github/riak_kv/deps/bitcask/_build/default/19.2.dialyzer_warnings</div><div class="">===> Warnings occured running dialyzer: 17</div><div class="">```</div><div class=""><br class=""></div><div class="">Particularly confusing, are errors like the first one </div><div class=""><br class=""></div><div class="">```</div><div class=""> 197: The call bitcask_fileops:close_for_writing(WriteFile::#filestate{mode::'read_only' | 'read_write' | 'undefined',filename::string(),tstamp::'undefined' | integer(),fd::'undefined' | port(),hintfd::port(),hintcrc::integer(),ofs::'undefined' | non_neg_integer(),l_ofs::non_neg_integer(),l_hbytes::non_neg_integer(),l_hintcrc::non_neg_integer()}) will never return since it differs in the 1st argument from the success typing arguments: ('fresh' | 'undefined')</div><div class="">```</div><div class=""><br class=""></div><div class="">I _think_ dialyzer is saying that the call `bitcask_fileops:close_for_writing(WriteFile#filestate{}, ...)` is not possible because of type violations when creating `#filestate{}` lower down the call stack.</div><div class=""><br class=""></div><div class="">Would appreciate if someone could help understand this better and also suggest how one separates noise from real warnings with dialyzer.</div><div class=""><br class=""></div><div class="">Best,</div><div class="">Raghav</div><div class=""><br class=""></div>
</div>
_______________________________________________<br class="">erlang-questions mailing list<br class=""><a href="mailto:erlang-questions@erlang.org" class="">erlang-questions@erlang.org</a><br class="">http://erlang.org/mailman/listinfo/erlang-questions<br class=""></div></blockquote></div><br class=""></body></html>