💨

[Bug #21535] 『メソッドの呼び出し方』によって発生する例外が異なるというバグ報告

に公開

[Bug #21535] NoMethodError becomes NameErrorwhen using ... delegation and method call indirection

  • ... を引数にしてメソッドを呼び出した場合に『そのメソッドの呼び出し方』によって発生する例外が異なるというバグ報告
  • 例えば次のように『存在しないメソッドを呼び出しているメソッド』を呼び出した場合は NoMethodError が発生する
class Test
  # 引数を ... で forward する
  def foo(...)
    nil.bar(...)
  end
end

begin
  Test.new.foo
rescue => e
  pp e
  # => #<NoMethodError: undefined method 'bar' for nil>
end
  • しかし、次のように『更に別のメソッドを経由して foo を呼び出す』場合に意図しない例外が発生する
    • こちらも同様に NoMethodError になってほしいが Ruby 3.4 では NameError になる
class Test
  def foo(...)
    nil.bar(...)
  end

  def foo_indirect
    foo
  end
end

begin
  Test.new.foo_indirect
rescue => e
  # Ruby 3.3 では NoMethodError が発生するが Ruby 3.4 では NameError になる
  pp e
  # Ruby 3.3 => #<NoMethodError: undefined method `bar' for nil>
  # Ruby 3.4 => #<NameError: undefined local variable or method 'bar' for nil>
end
  • ... の引数の forward に関しては他にもいくつか問題があったと思うのでそれ関連ですかねえ
  • 実際に原因となったコミットが forward 関連の最適化の影響みたい
  • ちなみに ... ではなくて *, **, & であれば問題ないので回避したい場合はそちらを利用する手段はあるみたいですね
class Test
  def foo(*, **, &)
    nil.bar(*, **, &)
  end

  def foo_indirect
    foo
  end
end

begin
  Test.new.foo_indirect
rescue => e
  # Ruby 3.3 では NoMethodError が発生するが Ruby 3.4 では NameError になる
  pp e
  # Ruby 3.3 => #<NoMethodError: undefined method `bar' for nil>
  # Ruby 3.4 => #<NoMethodError: undefined method 'bar' for nil>
end
GitHubで編集を提案

Discussion