<div dir="ltr">Hi all,<div><br></div><div>I recently encountered a rather strange, unexpected Dialyzer error. I'm unsure if this might be considered a Dialyzer bug, or if I'm just missing some key piece of knowledge that would help me understand what's going on here.</div><div><br></div><div>I took the code that generated the warning and pruned it down down to this:</div><div><br></div><div><div><font face="monospace, monospace">-module(opaque_weirdness).</font></div><div><font face="monospace, monospace">-export([public_func/0]).</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">-record(a, {</font></div><div><font face="monospace, monospace">    d = dict:new() :: dict:dict()</font></div><div><font face="monospace, monospace">}).</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">-record(b, {</font></div><div><font face="monospace, monospace">    q = queue:new() :: queue:queue()</font></div><div><font face="monospace, monospace">}).</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">public_func() -></font></div><div><font face="monospace, monospace">    add_element(#b{}, my_key, my_value).</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">add_element(#a{d = Dict}, Key, Value) -></font></div><div><font face="monospace, monospace">    dict:store(Key, Value, Dict);</font></div><div><font face="monospace, monospace">add_element(#b{q = Queue}, Key, Value) -></font></div><div><font face="monospace, monospace">    queue:in({Key, Value}, Queue).</font></div></div><div><font face="monospace, monospace"><br></font></div><div><font face="arial, helvetica, sans-serif">Which yields the following warning when I run it through Dialyzer:</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><div><font face="monospace, monospace">opaque_weirdness.erl:16: The attempt to match a term of type #b{q::queue:queue(_)} against the pattern {'a', Dict} breaks the opaqueness of queue:queue(_)</font></div><div style="font-family:arial,helvetica,sans-serif"><br></div></div><div style="font-family:arial,helvetica,sans-serif">It seems like this warning is somehow being triggered by the presence of the unused function clause in add_element. If I modify the code and add a line to public_func so that we use both clauses, then Dialyzer passes with no warnings.</div><div style="font-family:arial,helvetica,sans-serif"><br></div><div style="font-family:arial,helvetica,sans-serif">If I modify the above code to use tagged tuples instead of records (i.e. {dict, Dict} instead of #a{d = Dict}) then it gives a completely different warning, which makes much more sense to me:</div><div style="font-family:arial,helvetica,sans-serif"><br></div><div><font face="monospace, monospace">opaque_weirdness.erl:10: The pattern <{'queue', Queue}, Key, Value> can never match the type <{'dict',dict:dict(_,_)},'my_key','my_value'></font><br></div><div><font face="monospace, monospace"><br></font></div><div>So the use of records seems to be necessary to trigger the opaqueness warning, though I can't fathom why this should matter.</div><div><br></div><div>In the original example code, can anyone explain why Dialyzer is giving a warning about opaqueness instead of producing a "pattern X can never match the type Y" warning? The opaqueness warning seems really bizarre to me; obviously the term will never match the pattern, so how is opaqueness being broken?</div><div><br></div><div>Thanks,</div><div>Nick Marino</div></div>