Skip to content

[pull] master from ruby:master#1146

Merged
pull[bot] merged 11 commits into
turkdevops:masterfrom
ruby:master
Jun 24, 2026
Merged

[pull] master from ruby:master#1146
pull[bot] merged 11 commits into
turkdevops:masterfrom
ruby:master

Conversation

@pull

@pull pull Bot commented Jun 24, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

znz and others added 11 commits June 24, 2026 11:37
The RDoc `call-seq` for `Ractor#monitor` says it returns `self`, but the
method actually returns `true`/`false`.

It is implemented by `ractor_monitor()` in `ractor_sync.c`, which returns
only `Qtrue` or `Qfalse` — there is no code path that returns `self`:

- `true`  — the monitor was registered (the ractor is still running)
- `false` — the ractor had already terminated, so it was not registered;
  the termination message (`:exited` / `:aborted`) is sent to the port
  immediately

(For comparison, `Ractor#unmonitor` does `return self`, so its existing
`-> self` call-seq is correct and is left unchanged.)

This patch corrects the `call-seq` to `-> true or false` and documents the
meaning of the two return values.
…otiate PQC

OpenSSL >= 3.5 can ship ML-KEM and ML-DSA while still keeping them out
of the default negotiation lists, for example under RHEL's system-wide
crypto policies. The tests force a PQC-only server but connect with the
default gem fetcher, so they fail the handshake on such hosts even
though the version gate passes. Probe a real loopback handshake instead.

ruby/rubygems@ca011a9897

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The old `remove_unreachable_chunk` walked the dead code once and tried
to do two things at the same time -- count label references inside that
chunk and figure out what exactly to delete.

That breaks for loops -- the loop label comes before the jump back to it;
on the first walk, the label looks like it has no references inside the
chunk yet, so the optimizer thinks something outside the dead code still
needs it. It stops there and deletes only the setup code before the loop,
leaving the loop body behind.

I've changed the algorithm to use two passes to mitigate the issue;
I believe the performance overhead is neglible

```shell
$ ruby --parser parse.y -e 'if []; else; a => [*, 42, *]; end'
$ ruby --parser prism -e   'if []; else; a => [*, 42, *]; end'
-- raw disasm--------
   trace: 1
   0000 putnil                                                           (   1)
   0001 leave                                                            (   1)
 <L018> [sp: 1, unremovable: 0, refcnt: 1]
   0002 dup                                                              (   1)
   0003 topn                 2                                           (   1)
   0005 opt_le               <calldata:<=, 1>                            (   1)
   0007 branchunless         <L021>                                      (   1)
   0009 topn                 3                                           (   1)
   0011 topn                 1                                           (   1)
   0013 opt_aref             <calldata:[], 1>                            (   1)
   0015 putobject            42                                          (   1)
   0017 dupn                 2                                           (   1)
   0019 checkmatch           2                                           (   1)
   0021 dup                                                              (   1)
   0022 branchif             <L023>                                      (   1)
   0024 putspecialobject     1                                           (   1)
   0026 putobject            "%p === %p does not return true"            (   1)
   0028 topn                 3                                           (   1)
   0030 topn                 5                                           (   1)
   0032 opt_send_without_block <calldata:core#sprintf, 3>                (   1)
   0034 setn                 10                                          (   1)
   0036 putobject            false                                       (   1)
   0038 setn                 12                                          (   1)
   0040 pop                                                              (   1)
   0041 pop                                                              (   1)
 <L023> [sp: 4, unremovable: 0, refcnt: 1]
   0042 setn                 2                                           (   1)
   0044 pop                                                              (   1)
   0045 pop                                                              (   1)
   0046 branchif             <L020>                                      (   1)
   0048 putobject_INT2FIX_1_                                             (   1)
   0049 opt_plus             <calldata:+, 1>                             (   1)
   0051 jump                 <L018>                                      (   1)
 <L021> [sp: 1, unremovable: 0, refcnt: 1]
*  0053 adjuststack          3                                           (   1)
   0055 putspecialobject     1                                           (   1)
   0057 putobject            "%p does not match to find pattern"         (   1)
   0059 topn                 2                                           (   1)
   0061 opt_send_without_block <calldata:core#sprintf, 2>                (   1)
   0063 setn                 4                                           (   1)
   0065 putobject            false                                       (   1)
   0067 setn                 6                                           (   1)
   0069 pop                                                              (   1)
   0070 pop                                                              (   1)
   0071 jump                 <L012>                                      (   1)
 <L020> [sp: 1, unremovable: 0, refcnt: 1]
   0073 adjuststack          3                                           (   1)
   0075 pop                                                              (   1)
   0076 jump                 <L003>                                      (   1)
 <L012> [sp: -1, unremovable: 0, refcnt: 1]
   0078 pop                                                              (   1)
   0079 putspecialobject     1                                           (   1)
   0081 topn                 4                                           (   1)
   0083 branchif             <L024>                                      (   1)
   0085 putobject            NoMatchingPatternError                      (   1)
   0087 putspecialobject     1                                           (   1)
   0089 putobject            "%p: %s"                                    (   1)
   0091 topn                 4                                           (   1)
   0093 topn                 7                                           (   1)
   0095 opt_send_without_block <calldata:core#sprintf, 3>                (   1)
   0097 opt_send_without_block <calldata:core#raise, 2>                  (   1)
   0099 jump                 <L025>                                      (   1)
 <L024> [sp: -1, unremovable: 0, refcnt: 1]
   0101 putobject            NoMatchingPatternKeyError                   (   1)
   0103 putspecialobject     1                                           (   1)
   0105 putobject            "%p: %s"                                    (   1)
   0107 topn                 4                                           (   1)
   0109 topn                 7                                           (   1)
   0111 opt_send_without_block <calldata:core#sprintf, 3>                (   1)
   0113 topn                 7                                           (   1)
   0115 topn                 9                                           (   1)
   0117 opt_send_without_block <calldata:new, 3>                         (   1)
   0119 opt_send_without_block <calldata:core#raise, 1>                  (   1)
 <L025> [sp: -1, unremovable: 0, refcnt: 1]
   0121 adjuststack          7                                           (   1)
   0123 putnil                                                           (   1)
   0124 leave                                                            (   1)
 <L003> [sp: -1, unremovable: 0, refcnt: 1]
   0125 adjuststack          6                                           (   1)
   0127 putnil                                                           (   1)
   0128 leave                                                            (   1)
---------------------
-e:1: argument stack underflow (-2)
-e: compile error (SyntaxError)
```

Reproducible on every version since `3.4.0-preview2`
(`docker run -e ALL_RUBY_SHOW_DUP=yes -e ALL_RUBY_SINCE=3.4 --rm rubylang/all-ruby ./all-ruby -We 'if []; else; a => [*, 42, *]; end'`)

There seem to be another issue related to Prism's DCE & loops:

```shell
$ ruby --parser parse.y --dump insn -e 'if []; else; while true; end; end'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,33)>
0000 putnil                                                           (   1)[Li]
0001 leave
$ ruby --parser prism --dump insn -e 'if []; else; while true; end; end'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,33)>
0000 newarray                               0                         (   1)[Li]
0002 branchunless                           11
0004 putnil
0005 leave
0006 pop
0007 jump                                   11
0009 putnil
0010 pop
0011 jump                                   11
0013 putnil
0014 leave
```

the reason `branchunless` is not eliminated is that prism does not emit
`NODE_ZLIST` like `parse.y` does and instead emits `PM_ARRAY_NODE-0`
which is not treated as a always-truthy value by the peephole-optmizer.
Flatten bundler/lib, bundler/exe and bundler/bundler.gemspec into the
repository's top-level lib/, exe/ and bundler.gemspec to converge on the
flat layout ruby/ruby already uses. Bundler is fully require_relative
based, so the source move is mechanical and updates only the load-path
references in .rspec, .rubocop.yml, Rakefile, the spec path helper and
the CI workflows.

The Bundler docs stay under bundler/ for now and move in a later commit.

ruby/rubygems@916373ab9e
setup_command builds and installs the default Bundler gem from the
source tree. With Bundler flattened into the top-level lib/ and
bundler.gemspec, the separate "bundler/lib" library and the chdir into
bundler/ are gone: the single lib/ install now carries both RubyGems and
Bundler, and the gem is built straight from the top-level gemspec.

ruby/rubygems@3585865d3c
Move bundler/{CHANGELOG,LICENSE,README}.md to the top level as
CHANGELOG-bundler.md, LICENSE-bundler.md and README-bundler.md so they
no longer collide with the RubyGems documents while keeping the
CHANGELOG*/LICENSE*/README* prefixes that license scanners rely on.
bundler/.document is dropped since lib/bundler/.document already excludes
the runtime tree from RDoc, leaving bundler/ empty.

The single-document direction stays for a later docs merge; this only
de-collides the file names.

ruby/rubygems@db533d1651
Catch the leftover bundler/lib and bundler/exe references after the move:
the dev binstubs (bin/mdl, bin/rubocop, bin/test-unit), .gitattributes,
.codespellrc, the release tool version file, the rubygems_ext/ci_detector
cross-reference NOTE comments, and the developer documentation.

ruby/rubygems@821f51e297
After flattening, Bundler shares lib/ with RubyGems, so spec subprocesses
load the in-development Bundler from $LOAD_PATH instead of an installed
gem, the same way ruby-core already does. Four examples assumed a
separately installed Bundler and need updating.

The load-order example pre-activates bundler unconditionally (was
ruby_core? only) so Bundler.setup does not append the default bundler gem.

"does not reveal system gems" relied on bundler showing up in
installed_specs as an installed gem; flattened, bundler loads from
$LOAD_PATH and no longer appears there. Assert the example's actual intent
instead: the bundled gem stays visible and the system gem stays hidden
across Gem.refresh.

"bundle update --bundler" used `the_bundle.include_gems`, whose check
runs `ruby -e "require 'bundler'; Bundler.setup"`; the in-development
Bundler on $LOAD_PATH wins and its setup mismatches the locked version,
so both the bundler and myrack checks fail. Verify the resolved versions
through the binstub instead (`bundle --version` and `bundle list`), where
the self-manager activates the locked Bundler before reading the bundle.

"shows culprit file and line" double-loaded vendored Thor because the
system binstub activated the installed Bundler while $LOAD_PATH carried
the in-development one. Run it through the dev binstub so Bundler resolves
from a single place.

ruby/rubygems@2b7e876494
After flattening, lib/ holds both RubyGems and Bundler, so any dev binstub
that puts the worktree lib/ on $LOAD_PATH now overlays the already-booted
system RubyGems with the worktree one. bin/bundle hit this through the
Bundler gemspec activation: the partial overlay mixed a worktree Gem with
an older system Gem::ConfigFile, breaking native extension installs on Ruby
3.2/3.3 (undefined install_extension_in_lib) and corrupting spec names
elsewhere. The same overlay breaks bin/rake, bin/ronn, bin/rubocop and
bin/mdl, which unshift the worktree lib/ (or require it through
rubygems_ext) but boot on the system RubyGems. On a host whose RubyGems
differs from the worktree copy this double-loads files like rubygems/package
and raises (undefined method `spec=' for class Gem::Package::Old).

Route all of them through switch_rubygems, like bin/rspec and bin/test-unit
already do, so they re-exec onto the worktree RubyGems before anything is
loaded. Point the shared gem home job at the worktree copy too, since the
dev binstub can no longer load a separately installed RubyGems, and the
matrix is redundant for now.

ruby/rubygems@f50eb4216d
ruby/rubygems flattened the Bundler tree from bundler/ up to the
repository root, so repoint the rubygems mappings accordingly. Guard the
gemspec fixup with File.exist? too, since the synthetic parent tree built
for the flattening commit has no lib/bundler/bundler.gemspec yet.

ruby/rubygems#9634

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Method lookup for refinement super starts with the next active
refinement at the super call site, excluding the current refinment,
if such a refinement exists. This has been the behavior since Ruby
2.7, and it is now confirmed to be the desired behavior.
@pull pull Bot locked and limited conversation to collaborators Jun 24, 2026
@pull pull Bot added the ⤵️ pull label Jun 24, 2026
@pull pull Bot merged commit 815710f into turkdevops:master Jun 24, 2026
0 of 2 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants