How to fix type violation warning from a macro in Elixir 1.18

I have a macro that is used for parsing:

  defmacro left <~> right do
    quote do
      case unquote(left) do
        :error ->
          unquote(right)

        {:error, _} ->
          unquote(right)

        {:ok, _} = r ->
          r

        {:ok, _, _} = r ->
          r
      end
    end
  end

It is finding first thing that evaluates to {:ok, _} or {:ok, _, _} in a chain like parse1(args) <~> parse2(args) <~> parse3(args). We are using a macro because it is lazy. E.g. we only evaluate parse2(args) when parse1(args) failed.

In Elixir 1.18, I started getting warnings like this:

    warning: the following clause will never match:

        {:error, _}

    because it attempts to match on the result of:

        parse(args)

    which has type:

        dynamic(:error or {:ok, term()})

which is correct. This particular parser return only :error or {:ok, term()}, but other usages of this macro use othe paths including {error, _} and {:ok, _, _}.

So, the warning is technically correct, but doesn’t play well with the macro. How could I solve that issue?

Until there’s manual type notations you’d need to work around that, like discussed e.g. in

Hello,

In this case you could normalize the return types so errors are always a tuple.

1 Like