<div dir="ltr"><div dir="ltr" class="gmail_msg">The dialyzer often reports an error which really occurs somewhere else. Hence, if given an error which you don't know how to solve, it is often good to look for other errors which you do know how to solve. In turn, fixing those errors can clear up the call chain such that other errors become clearer or get resolved as no-error-in-the-first-place.<div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">The reason it is often confusing is that it is never wrong. Rather, the dialyzer tends to find a path in your code you never thought of. So you are thrown off by the structure of your own code which you think you know how runs. The trick is to throw away assumptions and go chase call chains. And fix those errors which you know how to fix early on. Once they are done, you can turn your eyes on the other errors.</div><div class="gmail_msg"><br></div><div class="gmail_msg">Case in point: I did a fix for a single dialyzer warning today. The error count went from about 43 to 24 on that project. The code looked like:</div><div class="gmail_msg"><br></div><div class="gmail_msg">foo(_, _, null) -> ok;</div><div class="gmail_msg">foo(_, _, X) -> ...CBody...</div><div class="gmail_msg"><br></div><div class="gmail_msg">The dialyzer said that the function wouldn't work because my use differed from foo's success typing: (any(), any(), null). What the dialyzer is saying is "there is a bug in CBody, so the function only works if being passed null". Since foo/3 had many uses all over the code base, they were reported with the same error.</div></div><br class="gmail_msg"><div class="gmail_quote gmail_msg"><div dir="ltr" class="gmail_msg">On Thu, Mar 2, 2017 at 6:39 PM Brujo Benavides <<a href="mailto:fernando.benavides@inakanetworks.com" class="gmail_msg" target="_blank">fernando.benavides@inakanetworks.com</a>> wrote:<br class="gmail_msg"></div><blockquote class="gmail_quote gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg">Hi Raghav,</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">  </span>I have a private gig at my company: I dialyze projects for beer (true story).</div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap"> </span>Let me show you an example of my mental process based on your commit. Let’s tackle like 197…</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">     </span>It reads:</div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">             </span>_ = bitcask_fileops:close_for_writing(WriteFile),</div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">     </span>And dialyzer is saying that the call to that function will never return since <b class="gmail_msg">it differs</b> the first <i class="gmail_msg">(and only)</i> argument can’t be <b class="gmail_msg">fresh</b> nor <b class="gmail_msg">undefined</b>.</div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>There are 3 possibilities here:</div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">       </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="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">     </span>2. WriteFile can actually be <b class="gmail_msg">fresh</b> or <b class="gmail_msg">undefined</b>, but dialyzer is fooled by a misplaced spec somewhere.</div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap"> </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="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap"> </span>Let’s discard #3… I bet your app is tested with 100% coverage, so that can’t happen.</div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">    </span>Let’s aim for #1. We have to check the bitcask_fileops:close_for_writing/1’s code. …and <b class="gmail_msg">bingo!</b> bitcask_fileops:close_for_writing/1 does have a third clause that, instead of <b class="gmail_msg">fresh</b> or <b class="gmail_msg">undefined</b> can receive a <b class="gmail_msg">#filestate{}</b> record (with some fixed params).</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">    </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="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">  </span>That’s bad, but check it out, that function is calling <b class="gmail_msg">close_hintfile/1</b> and we do have warnings for that one, specifically:</div></div><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><div class="gmail_msg"> 240: Function close_hintfile/1 has no local return</div><div class="gmail_msg"> 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="gmail_msg"> 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="gmail_msg"><br class="gmail_msg"></div></div><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap"> </span>Ok, so the function has no local return, that explains all! (o_O)</div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">     </span>Anyway, let’s check the last 2, shall we?</div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">   </span>On line 240, header of the first clause of the function, we’re using <b class="gmail_msg">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="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>- Matching of pattern {‘filestate’, …} tagged with a record name… => The pattern with record filestate that you are using…</div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">       </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="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">     </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="gmail_msg">hintfd </b>which is defined as <b class="gmail_msg">port()</b>.</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">  </span>So, it’s pretty clear that our intention was to allow hintfd to be <b class="gmail_msg">undefined</b>.</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">       </span>My next step here would be to fix that (as you did) and run rebar3 dialyzer again.</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">   </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="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">     </span>I’m not sure if this is what you were actually looking for, but maybe it helps anyway.</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><span class="m_-7998306137070614654m_-4799599609461880162Apple-tab-span gmail_msg" style="white-space:pre-wrap">     </span>Happy dialyzing! :)</div></div><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"><br class="gmail_msg"></div><br class="gmail_msg"><div class="gmail_msg"><blockquote type="cite" class="gmail_msg"><div class="gmail_msg">On Mar 2, 2017, at 06:39, Raghav Karol <<a href="mailto:raghav.karol@gmail.com" class="gmail_msg" target="_blank">raghav.karol@gmail.com</a>> wrote:</div><br class="m_-7998306137070614654m_-4799599609461880162Apple-interchange-newline gmail_msg"><div class="gmail_msg"><div dir="ltr" class="gmail_msg"><div class="gmail_msg">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="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">Using OTP-19, `rebar3 dialyzer` on this commit <a href="https://github.com/basho/bitcask/commit/cd74f59bfe47a39878d7a56a55ce0ae723723677" class="gmail_msg" target="_blank">https://github.com/basho/bitcask/commit/cd74f59bfe47a39878d7a56a55ce0ae723723677</a> produces: </div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">```</div><div class="gmail_msg">src/bitcask.erl</div><div class="gmail_msg"> 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="gmail_msg"> 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="gmail_msg"> 520: The created fun has no local return</div><div class="gmail_msg"> 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="gmail_msg"> 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="gmail_msg"> 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="gmail_msg"> 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="gmail_msg">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="gmail_msg">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="gmail_msg">1870: Function wrap_write_file/1 has no local return</div><div class="gmail_msg">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="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">src/bitcask_fileops.erl</div><div class="gmail_msg"> 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="gmail_msg"> 240: Function close_hintfile/1 has no local return</div><div class="gmail_msg"> 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="gmail_msg"> 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="gmail_msg"> 314: The pattern 'undefined' can never match the type port()</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">src/bitcask_merge_delete.erl</div><div class="gmail_msg"> 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="gmail_msg">===> Warnings written to /Users/raghav/github/riak_kv/deps/bitcask/_build/default/19.2.dialyzer_warnings</div><div class="gmail_msg">===> Warnings occured running dialyzer: 17</div><div class="gmail_msg">```</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">Particularly confusing, are errors like the first one </div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">```</div><div class="gmail_msg"> 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="gmail_msg">```</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">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="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">Would appreciate if someone could help understand this better and also suggest how one separates noise from real warnings with dialyzer.</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">Best,</div><div class="gmail_msg">Raghav</div><div class="gmail_msg"><br class="gmail_msg"></div>
</div>
_______________________________________________<br class="gmail_msg">erlang-questions mailing list<br class="gmail_msg"><a href="mailto:erlang-questions@erlang.org" class="gmail_msg" target="_blank">erlang-questions@erlang.org</a><br class="gmail_msg"><a href="http://erlang.org/mailman/listinfo/erlang-questions" class="gmail_msg" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br class="gmail_msg"></div></blockquote></div><br class="gmail_msg"></div>_______________________________________________<br class="gmail_msg">
erlang-questions mailing list<br class="gmail_msg">
<a href="mailto:erlang-questions@erlang.org" class="gmail_msg" target="_blank">erlang-questions@erlang.org</a><br class="gmail_msg">
<a href="http://erlang.org/mailman/listinfo/erlang-questions" rel="noreferrer" class="gmail_msg" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br class="gmail_msg">
</blockquote></div></div>