Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions internal/vm/object_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -1255,6 +1255,13 @@ func (vm *VM) classOf(v object.Value) *RClass {
// Logger::Formatter, whose #call renders one line through the library.
return vm.cLoggerFormatter
case *Set:
// A Set subclass instance carries its own class; nil is Set itself.
// Disabling this line fails 8 of the 12 rows of
// TestASetSubclassReportsItsOwnClass — see that test for which 4 do not,
// and why.
if x.cls != nil {
return x.cls
}
return vm.cSet
case *PrettyPrint:
return vm.cPrettyPrint
Expand Down
21 changes: 19 additions & 2 deletions internal/vm/prelude.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1560,8 +1560,25 @@ def join(sep = nil)
end

# to_set returns self (a Set is already a Set).
def to_set
self
# Set#to_set returns SELF only for a plain Set asked with no arguments; a
# subclass, an explicit klass, extra arguments or a block all build a new one
# (MRI's set.rb: `return self if instance_of?(Set) && klass == Set &&
# block.nil? && args.empty?`).
#
# ⛔ This was `def to_set; self; end`, which was INVISIBLE while every Set
# reported Set: returning self then answered Set whatever the receiver was, so
# it matched MRI by accident. Giving a subclass its own class (#903) made that
# accident a divergence — `Sub[1,2].to_set` answers Sub where MRI answers Set — so
# the guard is part of that change, not a separate cleanup. Measured on 4.0.7:
#
# Set[1,2].to_set.equal?(s) true Sub[1,2].to_set.class Set
# Set[1,2].to_set(Sub).class Sub Sub[1,2].to_set.equal?(sub) false
#
# It also closes an arity gap the no-argument form had: `to_set(Sub)` raised
# ArgumentError (given 1, expected 0).
def to_set(klass = Set, *args, &block)
return self if instance_of?(Set) && klass == Set && block.nil? && args.empty?
klass.new(self, *args, &block)
end
end

Expand Down
Loading
Loading