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
rb_warn diagnostics never fire: $VERBOSE is unset in vm.globals while Ruby reads it as false #641
VM.rbWarn is the VM's rb_warn equivalent: it writes to the current $stderr
unless $VERBOSE is nil, which is the gate MRI applies. But vm.globals["$VERBOSE"] starts unset, so object.IsNil sees a Go nil and
the helper returns early. Reading $VERBOSE from Ruby still answers false —
it comes from a different path — so nothing looks wrong.
The effect is that every rb_warn-class diagnostic this VM implements is
silent until a program assigns $VERBOSE itself. MRI prints them at the default $VERBOSE == false.
Reproduction:
# v.rbmoduleMM;K=1;K=2;endp:done
$ ruby v.rb
v.rb:1: warning: already initialized constant MM::K
v.rb:1: warning: previous definition of K was here
:done
$ rbgo v.rb
:done
Assigning it makes the warnings appear, which confirms the gate rather than the
call site is at fault:
$ rbgo -e '$VERBOSE = false; module MM; K = 1; K = 2; end'
warning: already initialized constant MM::K
Callers affected today (all of them correct code that simply never fires):
warnAlreadyInitialized — core/module/const_added_spec.rb's "records
re-definition of existing constants" and every other "already initialized constant" expectation.
The fix belongs in VM initialisation (give $VERBOSE its false default in vm.globals, where the reader already agrees), not in any individual warning.
Doing that will turn on a class of warnings across the suite at once, so it
wants its own measured change rather than riding along with a conformance PR.
Confirmed live on main @8f2a019, and here is the witness that makes it
unmistakable. A census of all 2206 *_spec.rb under language/+core/ puts 82 examples across 57 files behind this one gate — the largest single cause in
the campaign.
$ ruby -e 'X=1; X=2'
-e:1: warning: already initialized constant X
-e:1: warning: previous definition of X was here
$ rbgo -e 'X=1; X=2'
(nothing)
$ rbgo -e '$VERBOSE=false; X=1; X=2'
warning: already initialized constant X <-- it FIRES
Assigning $VERBOSE the value it already reads turns the warnings on. The
Ruby-visible read synthesises false, so the gate is invisible from inside the
language:
$ ruby -e 'p $VERBOSE.nil?' # false
$ rbgo -e 'p $VERBOSE.nil?' # false <-- identical, on both engines
So there are two representations of one value, and the gate reads the one nobody
writes: rbWarn tests object.IsNil(vm.globals["$VERBOSE"]), and that map entry
is never seeded at bootstrap, while the Ruby-level accessor synthesises false on
read. No Ruby-level probe can distinguish the two — which is why this survived so
long and why it is worth writing down as a shape, not just a fix.
Two companions that must land with it, or the examples still fail:
rbWarn omits the warnUplevelPrefix(0) that rbWarn1 applies, so messages
lose the -e:1: prefix MRI always emits (visible above);
the previous definition of X was here second line is never emitted at all —
a missing example, not a formatting difference.
A separate sub-finding from the same census, worth fixing in the same pass: the given block not used warning goes through two different helpers in one file — builtins.go:3106 uses rbWarning1 (which requires $VERBOSE == true) while :4428/:4456 use rbWarn1 (default level). MRI uses rb_warn for all of them,
so count/all?/any?/none?/one?/rindex and the rest of Enumerable stay
silent while find_index warns.
Owning file internal/vm/io_class.go:1133 plus the bootstrap seeding. Note that
PR #697 is currently open against io_class.go, so this wants to land after it.
Activity
tannevaled commentedon Sep 26, 2026
Confirmed live on
main@8f2a019, and here is the witness that makes itunmistakable. A census of all 2206
*_spec.rbunderlanguage/+core/puts82 examples across 57 files behind this one gate — the largest single cause in
the campaign.
Assigning
$VERBOSEthe value it already reads turns the warnings on. TheRuby-visible read synthesises
false, so the gate is invisible from inside thelanguage:
So there are two representations of one value, and the gate reads the one nobody
writes:
rbWarntestsobject.IsNil(vm.globals["$VERBOSE"]), and that map entryis never seeded at bootstrap, while the Ruby-level accessor synthesises
falseonread. No Ruby-level probe can distinguish the two — which is why this survived so
long and why it is worth writing down as a shape, not just a fix.
Two companions that must land with it, or the examples still fail:
rbWarnomits thewarnUplevelPrefix(0)thatrbWarn1applies, so messageslose the
-e:1:prefix MRI always emits (visible above);previous definition of X was heresecond line is never emitted at all —a missing example, not a formatting difference.
Both are tracked in #699.
A separate sub-finding from the same census, worth fixing in the same pass: the
given block not usedwarning goes through two different helpers in one file —builtins.go:3106usesrbWarning1(which requires$VERBOSE == true) while:4428/:4456userbWarn1(default level). MRI usesrb_warnfor all of them,so
count/all?/any?/none?/one?/rindexand the rest of Enumerable staysilent while
find_indexwarns.Owning file
internal/vm/io_class.go:1133plus the bootstrap seeding. Note thatPR #697 is currently open against
io_class.go, so this wants to land after it.internal/vm: one gate and one composition for rb_warn, so the diagnos…