elixir-lang / elixir

Elixir is a dynamic, functional language for building scalable and maintainable applications

Home Page:https://elixir-lang.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Pinning does not seem to work in 'else' block of 'with' special form

jamesvl opened this issue · comments

Elixir and Erlang/OTP versions

Erlang/OTP 27 [erts-15.0] [source] [64-bit] [smp:32:16] [ds:32:16:10] [async-threads:1] [jit:ns]

Elixir 1.17.0 (compiled with Erlang/OTP 27)

(neither the warning nor the buggy behavior occurs in Elixir 1.16)

Operating system

Linux / Fedora 40

Current behavior

According to the docs, the else block of the with special form is supposed to behave like a case clause.

The following minimal example shows a warning in Elixir 1.17 and running the code in iex shows that the first clause in the else block always matches any parse error in tuple form:

defmodule BugEx do
  def spurious_warning(val) do
    example_str = "abc"

    with(
      {int_val, ""} <- Integer.parse(val)
    )
    do
      int_val + 0
    else
      {_x, ^example_str} ->
        {:error, "#{example_str} is a bad integer and oh this clause always matches"}

      {_x, str} ->
        {:error, "#{str} is not valid"}
    end
  end
end

And in iex:

$iex -S mix
Erlang/OTP 27 [erts-15.0] [source] [64-bit] [smp:32:16] [ds:32:16:10] [async-threads:1] [jit:ns]

Interactive Elixir (1.17.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> BugEx.spurious_warning("1abc")
{:error, "abc is a bad integer and oh this clause always matches"}
iex(2)> BugEx.spurious_warning("1abcd")
{:error, "abcd is a bad integer and oh this clause always matches"}

Expected behavior

Expected it to resped the pinned variable like a case clause would and Elixir 1.16 does:

# same code as above, but running on 1.16.13
$iex -S mix
Erlang/OTP 27 [erts-15.0] [source] [64-bit] [smp:32:16] [ds:32:16:10] [async-threads:1] [jit:ns]

Interactive Elixir (1.16.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> BugEx.spurious_warning("1abc")
{:error, "abc is a bad integer and oh this clause always matches"}
iex(2)> BugEx.spurious_warning("1abcd")
{:error, "abcd is not valid"}
iex(3)>

@jamesvl thank you for reporting 💜
I now understand what is going on.
This is due to #13299, we're not translating the pin operator as where x === pinned guards here as we should for functions.
Will try to send a fix ASAP.