2022/08/25 今回の気になった bugs.ruby のチケット

今週は lazy.take(0) した時に期待した挙動にならないというバグ報告がありました。

[Bug #18972] String#byteslice should return BINARY (aka ASCII-8BIT) Strings

# 今はレシーバのエンコーディングになっている
p "fée".byteslice(1).encoding
# => #<Encoding:UTF-8>
p "fée".byteslice(1).valid_encoding?
# => false
  • 期待する挙動は以下の通り
p "fée".byteslice(1).encoding
# => #<Encoding:ASCII-8BIT>
p "fée".byteslice(1).valid_encoding?
# => true

[Bug #18971] Enumerator::Lazy.take(0) leaks first element into next operation

  • 以下のように lazytake(0) を使用した時は期待する挙動になる
(2..10).take(0).to_a # => []
(2..10).take(0).map(:&itself).to_a # => []
(2..10).lazy.take(0).to_a # => []
  • しかし、以下のように take(0) した後に別の操作をすると期待する挙動にならないというバグ報告
p (2..10).lazy.take(0).map(&:itself).to_a # => [2]
p (2..10).lazy.take(0).select(&:even?).to_a # => [2]
p (2..10).lazy.take(0).select(&:odd?).to_a # => []
p (2..10).lazy.take(0).reject(&:even?).to_a # => []
p (2..10).lazy.take(0).reject(&:odd?).to_a # => [2]
p (2..10).lazy.take(0).take(1).to_a # => [2]
p (2..10).lazy.take(0).take(0).take(1).to_a # => [2]
p (2..10).lazy.take(0).drop(0).to_a # => [2]
p (2..10).lazy.take(0).find_all {|_| true}.to_a # => [2]
p (2..10).lazy.take(0).zip((12..20)).to_a # => [[2, 12]]
p (2..10).lazy.take(0).uniq.to_a # => [2]
p (2..10).lazy.take(0).sort.to_a # => []
p (2..2).lazy.take(0).sort.to_a # => []

[Bug #18974] Wrong line number in the rescue iseq for the exception matching code

  • iseq の出力と rescue => e している箇所の行番号がズレているというバグ報告
    • コード上は4行目になっているが iseq の出力では5行目になっている
def foo
  begin
    raise 'error'
  rescue => e
    puts e.message
  end
end

puts RubyVM::InstructionSequence.of(method :foo).disasm
__END__
== disasm: #<ISeq:foo@/tmp/vL5efqT/19:1 (1,0)-(7,3)> (catch: TRUE)
== catch table
| catch type: rescue st: 0000 ed: 0005 sp: 0000 cont: 0006
| == disasm: #<ISeq:rescue in foo@/tmp/vL5efqT/19:4 (4,2)-(5,18)> (catch: TRUE)
| local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
| [ 1] $!@0
| 0000 getlocal_WC_0                          $!@0                      (   5)[Li]
| 0002 putobject                              StandardError
| 0004 checkmatch                             3
| 0006 branchunless                           20
| 0008 getlocal_WC_0                          $!@0                      (   4)
| 0010 setlocal_WC_1                          e@0
| 0012 putself                                                          (   5)
| 0013 getlocal_WC_1                          e@0
| 0015 opt_send_without_block                 <calldata!mid:message, argc:0, ARGS_SIMPLE>
| 0017 opt_send_without_block                 <calldata!mid:puts, argc:1, FCALL|ARGS_SIMPLE>
| 0019 leave
| 0020 getlocal_WC_0                          $!@0
| 0022 throw                                  0
| catch type: retry  st: 0005 ed: 0006 sp: 0000 cont: 0000
|------------------------------------------------------------------------
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] e@0
0000 putself                                                          (   3)[LiCa]
0001 putstring                              "error"
0003 opt_send_without_block                 <calldata!mid:raise, argc:1, FCALL|ARGS_SIMPLE>
0005 nop                                                              (   1)
0006 leave                                                            (   7)[Re]

[Feature #18408] Allow pattern match to set instance variables

  • パターンマッチでインスタンス変数への束縛を許容したいチケット
  • 現状はパターンマッチでインスタンス変数に対して値を束縛する事ができない
# これはエラーになる
case {name: "John", age: 42}
in name: /jo/ => @name, age: @age
end

puts [@name, @age] #=> ["John", 42]
  • 上記のようにインスタンス変数でも束縛したいことがチケットの内容になる
  • これに関しては以前から議論されていたんですが現時点では『ローカル変数以外はサポートしない』という意思決定がされたようです