You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A String subclass is refused by $/, $-0, $\ and $, where MRI accepts it #884
Assigning an instance of a Stringsubclass to $/, $-0, $\ or $, raises TypeError in rbgo. MRI accepts it.
Measured
$ rbgo -e 'sub = Class.new(String); $VERBOSE=nil; $/ = sub.new("abc")'-e:1:in '<main>': value of $/ must be String (TypeError)
$ ruby -vruby 4.0.7 (2026-09-15 revision 229531a6cf) +PRISM [arm64-darwin25]
$ ruby -e 'sub = Class.new(String); $VERBOSE=nil; $/ = sub.new("abc"); p $/.class'String
Cause
internal/vm/globals.gocheckStrGvar decides with a Go type assertion:
if_, ok:=v.(*object.String); !ok {
raise("TypeError", "value of %s must be String", name)
}
A *object.String is class String by construction in rbgo (classOf maps the Go type straight to vm.cString), so an instance of a subclass is a different Go value and fails the assertion. MRI's check is T_STRING, which a subclass still is — rb_str_setter calls StringValue-style validation on the type, not the class.
Why it matters now
It is why language/predefined_spec.rb's
it"makes a new frozen String from the assigned String"dostring_subclass=Class.new(String)str=string_subclass.new("abc")str.instance_variable_set(:@ivar,1)
$/ =str
...
still fails after the Ruby 4.0 record-separator work: the example never reaches the freezing rule, because the assignment is refused one step earlier. I found this while implementing that rule and deliberately did not widen the assertion inside it — the two are separate changes, and this one touches every $x must be String global, not just the two that 4.0 changed.
Scope
The same assertion guards $/, $-0, $\ and $, (and checkFieldSepGvar has the same shape for $;/$-F, which additionally accepts a Regexp). A fix should establish how rbgo answers "is this value a String, subclasses included" once, rather than per-setter.
Activity
$/ and $-0 stop storing the object they were handed (#886)