Erlang/OTP 21 [erts-10.0.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]
Elixir 1.7.2 (compiled with Erlang/OTP 21)
Dialyzer produces warnings on generated exception-handling code in the try macro when a rescue clause matches on ErlangError. Minimal example:
defmodule TryTupleSize do
def demo do
try do
:erlang.error(:badarg)
rescue
e in ErlangError ->
{:ok, e}
end
end
end
Dialyzer output:
try_tuple_size.ex:6: Guard test tuple_size(__@5::#{'__exception__':='true', '__struct__':=_, _=>_}) can never succeed
The decompiled-to-Erlang version of the demo/0 function:
demo() ->
try
error(badarg)
catch
error:__@3:___STACKTRACE__@1 when not is_map(__@3) ->
_e@1 =
'Elixir.Exception':normalize(error,
__@3,
case __@3 of
__@5
when
tuple_size(__@5)
==
2
andalso
element(1,
__@5)
==
badkey;
__@5 == undef;
__@5
==
function_clause ->
___STACKTRACE__@1;
_ ->
[]
end),
{ok,_e@1};
error:#{'__struct__' := __@4,'__exception__' := true} = __@3:___STACKTRACE__@1
when __@4 == 'Elixir.ErlangError' ->
_e@1 =
'Elixir.Exception':normalize(error,
__@3,
case __@3 of
__@5
when
tuple_size(__@5)
==
2
andalso
element(1,
__@5)
==
badkey;
__@5 == undef;
__@5
==
function_clause ->
___STACKTRACE__@1;
_ ->
[]
end),
{ok,_e@1}
end.
In the case where the (second) generated catch branch has already matched on an exception map/struct, it should not use tuple_size/1 in that clause. Furthermore, since it has already established that the error has been normalized, it shouldn't be trying to normalize the error again. This could remove the type warning from the generated code.
Great report! While we could try to remove the extra cases from the second clause, in the future we will rather merge those two clauses into one to avoid code duplication, so I propose that we annotate the whole case inside normalize as generated to avoid the warning.
@seancribbs what did you use to decompile elixir code into erlang?
@eksperimental probably https://github.com/michalmuskala/decompile
Should this be fixed in 1.7.4 or is this only fixed in an upcoming 1.8?
Most helpful comment
Should this be fixed in 1.7.4 or is this only fixed in an upcoming 1.8?