[erlang-questions] Strange Dialyzer behavior when matching record fields with opaque types
Kostis Sagonas
kostis@REDACTED
Thu Jan 19 01:07:44 CET 2017
On 01/18/2017 05:24 PM, Nick Marino wrote:
> Hi Kostis,
>
> Thanks for the quick and helpful response! Glad I'm not crazy after all
> :). That all makes sense, and in my original use case that uncovered
> this, I'm fine with just commenting out the unused code for now.
>
> I also just uncovered a related(?) issue, in case anyone is interested:
> in my example code, I found that changing #b{} to #a{} in the call to
> add_element actually causes Dialyzer to crash. Here's the error message:
>
> Proceeding with analysis...{"init terminating in
> do_boot",{function_clause,[{dialyzer,message_to_string,[{opaque_match,["pattern
> <{'b', Queue}, Key,
> Value>","<#a{d::dict:dict(_,_)},'my_key','my_value'>"]}],[{file,"dialyzer.erl"},{line,310}]},{dialyzer,format_warning,2,[{file,"dialyzer.erl"},{line,300}]},{dialyzer_cl,'-print_warnings/1-lc$^0/1-0-',2,[{file,"dialyzer_cl.erl"},{line,818}]},{dialyzer_cl,print_warnings,1,[{file,"dialyzer_cl.erl"},{line,818}]},{dialyzer_cl,return_value,2,[{file,"dialyzer_cl.erl"},{line,715}]},{dialyzer_cl,do_analysis,4,[{file,"dialyzer_cl.erl"},{line,405}]},{dialyzer,'-cl/1-fun-0-',1,[{file,"dialyzer.erl"},{line,153}]},{dialyzer,doit,1,[{file,"dialyzer.erl"},{line,243}]}]}}
>
> I'm tempted to try and debug this myself, but I'm not sure I have the
> necessary skills and background to safely make changes to a tool like
> Dialyzer. Figured I should leave this one to the experts ;)
Thanks again for reporting this issue, which I can reproduce. One can
easily avoid the crash by the following patch:
================================================================
diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl
index d25ffd0..d5352fd 100644
--- a/lib/dialyzer/src/dialyzer.erl
+++ b/lib/dialyzer/src/dialyzer.erl
@@ -438,6 +438,8 @@ message_to_string({opaque_guard, [Arg1, Infix, Arg2,
ArgNs]}) ->
message_to_string({opaque_guard, [Guard, Args]}) ->
io_lib:format("Guard test ~w~s breaks the opacity of its argument\n",
[Guard, Args]);
+message_to_string({opaque_match, [Pat, Term]}) ->
+ io_lib:format("The ~s can never match the term ~s\n", [Pat, Term]);
message_to_string({opaque_match, [Pat, OpaqueType, OpaqueTerm]}) ->
Term = if OpaqueType =:= OpaqueTerm -> "the term";
true -> OpaqueTerm
================================================================
which produces the following warning in your example program:
opaque_weirdness.erl:13: The pattern <{'b', Queue}, Key, Value> can
never match the term <#a{d::dict:dict(_,_)},'my_key','my_value'>
However, this patch is sub-optimal. Similarly to the previous issue you
reported the core of the problem is that dialyzer erroneously classifies
the problem as opaque-related, which is not. It's a simple case of dead
code (a clause that will never match) and the warning should be tagged
with 'pattern_match' instead of 'opaque_match' or, better yet, simply
say that the 2nd clause is unused (cannot match).
I will leave this issue to the responsible developer at Ericsson to
handle properly.
Kostis
PS. The test case is:
-module(opaque_weirdness).
-export([public_func/0]).
-record(a, {d = dict:new() :: dict:dict()}).
-record(b, {q = queue:new() :: queue:queue()}).
public_func() ->
add_element(#a{}, my_key, my_value).
add_element(#a{d = Dict}, Key, Value) ->
dict:store(Key, Value, Dict);
add_element(#b{q = Queue}, Key, Value) ->
queue:in({Key, Value}, Queue).
More information about the erlang-questions
mailing list