2021/03/18 今週の気になった bugs.ruby のチケット

内容は適当です。
今週と言っても今週みかけたチケットなだけでチケット自体は昔からあるやつもあります。
あくまでも『わたしが気になったチケット』で全ての bugs.ruby のチケットを載せているわけではありません。

[PR irb #202] process multi-line pastes as a single entity

  • 現行の irb だと以下のようなコードをペーストするとエラーになる
class A
  def a; self; end
  def b; true; end
end

a = A.new

a
 .a
 .b
irb(main):001:1* class A
irb(main):002:1*   def a; self; end
irb(main):003:1*   def b; true; end
irb(main):004:0> end
 = > :b
irb(main):005:0>
irb(main):006:0> a = A.new
 = > #<A:0x00005588503197b8>
irb(main):007:0>
irb(main):008:0> a
 = > #<A:0x00005588503197b8>
irb(main):009:0>  .a
/home/worker/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/irb-1.3.4/lib/irb/workspace.rb:116:in `eval': (irb):9: syntax error, unexpected '.' (SyntaxError)
    from /home/worker/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/irb-1.3.4/exe/irb:11:in `<top (required)>'
    from /home/worker/.rbenv/versions/3.0.0/bin/irb:23:in `load'
    from /home/worker/.rbenv/versions/3.0.0/bin/irb:23:in `<main>'
irb(main):010:0>  .b
  • これはペーストしたタイミングで Ruby のコードが逐次的に評価され .a を呼び出した時にエラーになってしまっているため
    • 先に a のコードが評価され
  • これを回避するためにペーストして『最後に』コードを評価するようにする PR
  • 個人的には落とし所としてはいいとは思う

[Bug #17571] prependしたArray#[] が反映されない

  • 以下のように Arrayprepend してる #[] が呼び出されないことがある
module TestMod
  def [](*)
    :called
  end
end
Array.prepend TestMod

# これは Array#[] が呼ばれる
p [1, 2, 3][1]
# => 2

# これは TestMod#[] が呼ばれる
p [1, 2, 3][]
# => :called

# Method オブジェクトは TestMod を指している
p [1, 2, 3].method(:[])
# => #<Method: Array(TestMod)#[](*) /tmp/vud3mdg/27:2>
  • これはおそらく Array#[] を事前にメソッドキャッシュしておりそちらを優先して呼び出しているのが原因ぽい?
    • なので prepend しているメソッドは呼ばれなくなっている
    • 引数がない場合は Array#[]シグネチャが異なるのでキャッシュされたメソッドではなくて prepend されたメソッドを呼び出しているので意図する挙動になっているみたい?
  • これは Ruby 2.7 では問題なくて Ruby 3.0 から問題になっている
    • Ruby 3.0 に上げるタイミングでなにか壊れるかもしれないので注意したい
  • 原因っぽいコミット(と PR)

[Bug #17725] Prepend breaks ability to override optimized methods

  • 以下のように String.prepend すると String#+ が上書きされたりされなかったりする
# これは上書きされる
class String
  def + other
    'blah blah'
  end
end

p 'a' + 'b'
# => "blah blah"
# これは上書きされない
String.prepend(Module.new)
class String
  def + other
    'blah blah'
  end
end

p 'a' + 'b'
# => "ab"
  • これは Ruby 3.0 で再現する
    • Ruby 2.7 では再現しない
    • Ruby 3.0 に上げると急にぶっ壊れるかもしれないので注意する…

[Bug #16996] Hash should avoid doing unnecessary rehash

[Bug #17719] Irregular evaluation order in hash literals

  • Hash リテラルでキーが重複している場合に以下のような評価順になる
# 1個目と2個目の foo の要素が先に評価される
$ ruby -e '{foo:p(1), bar:p(2), foo:p(3)}'
-e:1: warning: key :foo is duplicated and overwritten on line 1
1
3
2