Elixir: Guard test tuple_size(...) can never succeed warning

Created on 1 Sep 2018  路  4Comments  路  Source: elixir-lang/elixir

Environment

  • Elixir & Erlang/OTP versions (elixir --version):
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)
  • Operating system: Mac OS/X High Sierra 10.13.6

Current behavior

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.

Expected behavior

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.

Elixir (compiler) Bug Intermediate

Most helpful comment

Should this be fixed in 1.7.4 or is this only fixed in an upcoming 1.8?

All 4 comments

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?

Should this be fixed in 1.7.4 or is this only fixed in an upcoming 1.8?

Was this page helpful?
0 / 5 - 0 ratings