Skip to content

[pull] master from ruby:master#994

Merged
pull[bot] merged 34 commits intoturkdevops:masterfrom
ruby:master
May 8, 2026
Merged

[pull] master from ruby:master#994
pull[bot] merged 34 commits intoturkdevops:masterfrom
ruby:master

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented May 8, 2026

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 : )

XrXr and others added 30 commits May 7, 2026 16:04
Previously, we kept around `PatchPoint`s after patching them for several
kinds of invariants. That wasted compute since repeated invalidation
with the same key patched a growing list of patchpoints each time,
making it accidentally O(n^2). Retaining the patchpoints also used memory.

Some invariants, such as rb_zjit_invalidate_no_singleton_class() and
rb_zjit_invalidate_root_box(), already remove from the table. This commit
makes all invariants remove from the table.
The ripper translator is a good resource when porting ripper usage over to prism

A few places use `visit_token` when it can be more specific.
A call operator for example can ever only be one of three things.
A positional argument can only ever be a identifier (no constant, no global, etc.)

Also removes some stale comments. There are `*_TargetNode` for these now.

ruby/prism@62511d59a2
This would allow rb_gc_event_hook to run in a GC thread that is a
non-Ruby thread.
…les ($! and $@)

Ruby::Box fix stale cached values for exception-related global variables ($! and $@)

The exception-related virtual variables $! (current exception) and
$@ (its backtrace) are stored on the execution context (ec->errinfo
and the rescue/ensure frame's local slot accessed via errinfo_place),
not in box->gvar_tbl. Caching their values in box->gvar_tbl makes the
second read return a stale value from the previous raise/rescue:

```
begin; raise "first";  rescue; p $!; end
begin; raise "second"; rescue; p $!; end
# before: #<RuntimeError: first> / #<RuntimeError: first>
# after:  #<RuntimeError: first> / #<RuntimeError: second>
```

```
begin; raise "first";  rescue; p $@.first; end
begin; raise "second"; rescue; p $@.first; end
# before: same backtrace returned for both
# after:  distinct backtrace per raise
```

Fixes [Bug #21991](https://bugs.ruby-lang.org/issues/21991)
Related PR: #16303
To the code where they are actually initialized.
…ault

Add the recent developer meeting, we discussed switching from using
pessimistic versioning by default to using optimistic versioning by
default. This is the a step in that direction. It makes bundle add
without a explicit version given to use >= (optimistic) instead of
~> (pessimistic).

With this, the bundle add --optimistic option is now ignored, since
the behavior is now the default. This add a --pessimistic option to
set a pessimistic version.

ruby/rubygems@eed378086b
Definition#apply_override_to, Definition#converge_dependencies, and
Resolver#apply_overrides each duplicated the same find expression.
Centralizing it on Override prepares for upcoming fields (and the :all
target) without repeating the predicate in every call site.

ruby/rubygems@0c4424d5f3

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…uation time

Before this change, `override "rails", version: "not a version"` was
accepted by Bundler::Dsl#override and only failed later when the
resolver tried to instantiate Gem::Requirement. Surface the error at
the Gemfile evaluation step so the user sees it on the offending line.

ruby/rubygems@2ae83fbb4f

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ockfile

Lock the byroot policy decision (overrides are a Gemfile concept and
must not be serialized into Gemfile.lock) with a regression test, so a
future change that starts emitting override metadata in the lock would
fail loudly.

ruby/rubygems@9524b785c5

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rsion overrides

Extend the override DSL whitelist so per-gem metadata fields can be
declared. The :all target is rejected for now with a "not yet
supported" error so the field is purely per-gem until the next step
adds :all propagation.

ruby/rubygems@f9e4d7bf29

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When a spec's runtime dependencies are gathered for the resolver, its
required_ruby_version / required_rubygems_version metadata flow as
synthetic Ruby\0 / RubyGems\0 dependencies. Rewrite those before
they reach the dependency hash so per-gem overrides on those fields
take effect during resolution.

ruby/rubygems@853e00f778

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The per-dep loop in converge_dependencies only knows about version:
overrides via apply_override_to + matches_spec?. Metadata overrides
on direct deps were therefore invisible to lockfile change detection
and would silently no-op against an existing lock. Extend
converge_overrides_outside_dependencies to also unlock direct deps
when the override targets a non-version field.

ruby/rubygems@fdd4c30523

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…sion overrides

Add integration coverage exercising :ignore_upper and nil overrides
against per-gem metadata fields, transitive propagation, and lockfile
re-resolution when a metadata override is added against an existing
lockfile. The cases drive `bundle lock` so they exercise the resolver
without RubyGems' install-time required_ruby_version gate, which is
addressed in a later step.

ruby/rubygems@ec3a549df7

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Remove the temporary "not yet supported" guard so a Gemfile may write
`override :all, required_ruby_version: :ignore_upper` and similar
forms. The version: ban for :all stays — version requirements are
inherently per-gem.

ruby/rubygems@af09f0360a

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Override.find_for now returns the per-gem entry when present and
otherwise the matching :all entry on the same field. This is the
single dispatch point for overrides in Definition and Resolver, so
the fallback is what wires :all into resolution and lockfile change
detection without further plumbing.

ruby/rubygems@ef24b4eef9

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…sent

An :all override applies to every gem's metadata, so we have no way to
know which locked entries it affects without re-resolving. Force-unlock
them all when an :all override appears so the resolver gets a fresh
chance to apply the override.

ruby/rubygems@4f61f6813e

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Exercise :all required_ruby_version overrides applied to multiple gems
at once, the per-gem precedence rule, and re-resolution against an
existing lockfile when an :all override is introduced.

ruby/rubygems@81f2bfcf9b

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
matches_current_ruby? / matches_current_rubygems? now look up the
current Definition's overrides via Bundler.overrides and apply them
before checking against the runtime Ruby/RubyGems version. This
covers Installer#ensure_specs_are_compatible! and the materialize-
layer choose_compatible / SpecSet#valid? checks uniformly without
plumbing overrides through every materialization site.

When no Definition is set yet (e.g. RubyGems-side calls outside a
Bundler.definition block), Bundler.overrides returns an empty list
and the methods fall through to their original behavior.

ruby/rubygems@afe9313b6e

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drive bundle install end-to-end with a gem whose required_ruby_version
or required_rubygems_version excludes the current runtime, asserting
that a per-gem override (and an :all override) makes the install
succeed instead of erroring at the install-time compatibility gate.

ruby/rubygems@dbc9f24269

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bundler::Dsl#override now records caller_locations(1, 1).first on
each Override so the originating Gemfile line can be surfaced in
later diagnostics.

ruby/rubygems@ef73385cdc

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Append the list of currently active overrides (with Gemfile location,
when known) to the SolveFailure message so a user investigating a
"could not find compatible versions" error sees what override changed
the constraint set instead of being misled by the resolver-reported
requirement.

ruby/rubygems@10b8b53270

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Update the OVERRIDE section to cover the :all target, the
required_ruby_version / required_rubygems_version fields, and the
diagnostic shown on resolve failure.

ruby/rubygems@ac90c83b1b

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ler global

Phase 2.C wired overrides into MatchMetadata via Bundler.overrides, a
process-wide accessor read every time a spec answered
matches_current_metadata?. That leaked the user's Gemfile overrides
into Bundler-internal callers like SelfManager#remote_specs, where
overrides have no business: a Gemfile override could let bundle
self-update consider Bundler releases that are actually incompatible
with the running Ruby/RubyGems.

Revert MatchMetadata's matches_current_ruby? and matches_current_rubygems?
to evaluate the spec's own metadata, and add explicit
matches_current_*_with_overrides? variants. Pass overrides explicitly:
Installer#ensure_specs_are_compatible! gets them from @Definition,
LazySpecification#choose_compatible reads its newly-added @OVERRIDES
attribute, and SpecSet#valid? reads @OVERRIDES set on the SpecSet.
Definition propagates @OVERRIDES to the SpecSets it constructs and to
the LazySpecs they contain. SelfManager and other callers that should
keep evaluating real gemspec metadata reach the strict path
unchanged.

ruby/rubygems@e0ff753bbb

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously, any :all override called unlock_all_locked_specs_for_override
which pushed every locked spec into @gems_to_unlock. A user adding a
narrow `override :all, required_ruby_version: :ignore_upper` thus paid
for a full re-resolve that could pull unrelated dependency
upgrades/downgrades.

Make :all overrides leave the lockfile alone at converge time. They
take effect on a fresh resolution (no lockfile) or when the user opts
in via `bundle update`. Per-gem overrides retain their unlock for the
named gem since the user explicitly named the target.

ruby/rubygems@3c95ab99e3

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…reuse paths

Definition#resolve falls back to an existing lockfile when nothing
about the Gemfile or the locked deps changed. The two SpecSet rebuild
paths (deleted_deps subset and the redundant-platform-specific-gems
fallback) constructed fresh SpecSet instances without carrying
@OVERRIDES forward, so any LazySpec produced from them lost its
override context. After Step G that mattered: an :all metadata
override does not pre-unlock anything by design, which means it must
flow through these reuse paths intact.

Without it, the materialize layer either silently re-resolved (which
churns the lockfile) or, on the install-time check, fell back to the
spec's strict required_ruby_version metadata. Calling with_overrides
on both rebuilt SpecSets keeps the install-time behavior consistent
across resolve and lockfile-reuse paths.

ruby/rubygems@81fb91a8b1

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hsbt and others added 4 commits May 8, 2026 06:43
…tion set

SpecSet#incomplete_specs_for_platform constructed a fresh
self.class.new(@specs) for platform validation but never copied
@OVERRIDES. Platform-validity decisions therefore evaluated strict
required_ruby_version / required_rubygems_version metadata even when
resolution was running with overrides, so a metadata override could
allow a gem everywhere except platform validation, where the platform
might be marked incomplete and pruned.

Carry @OVERRIDES forward via with_overrides on the cloned SpecSet.

ruby/rubygems@11b7c58a5a

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…Spec overrides

SpecSet#with_overrides cascaded into each contained spec via
`respond_to?(:overrides=)`. RemoteSpecification#respond_to? forwards
to _remote_specification, which materializes the backing gemspec just
to answer the predicate. spec/runtime/require_spec.rb verifies that
Bundler does not load gemspecs it does not need by deliberately
poisoning one with `raise 'broken gemspec'`; the cascade tripped that
guard and made `Bundler.setup` blow up.

Gate the cascade on `is_a?(LazySpecification)` instead. Only
LazySpecification declares `attr_accessor :overrides` (used by
`#choose_compatible`), so the predicate is equivalent for any spec we
ever set overrides on, and it never triggers the lazy gemspec load.

ruby/rubygems@2a1e7d5c23

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SpecSet previously kept its own @OVERRIDES and a with_overrides setter
that had to be chained on every SpecSet.new(...) site (~13 sites in
Definition alone). Two Codex review rounds both flagged forgotten
chains in different SpecSet construction paths, which is exactly the
class of bug the chain pattern invites: it is purely "remember to
write" with no compiler help.

Move the override list to LazySpecification#overrides instead. The
LazySpec is the natural carrier — it is the value object the resolver
and install paths already pass around, and choose_compatible already
read overrides off it. Override.attach(specs, overrides) is added as
the dual of Override.find_for so Definition (after lockfile load) and
Resolver (after solve_versions) can populate the overrides on every
LazySpec they hand out, and LazySpecification.from_spec carries the
list forward when one LazySpec spawns another. Generic spec types
(StubSpecification, plain Gem::Specification, RemoteSpecification)
are intentionally ignored so generic metadata callers (SelfManager,
materialize-time strict checks) keep their current strict semantics.

SpecSet drops attr_accessor :overrides, the @OVERRIDES initialisation,
the with_overrides cascade, and reverts SpecSet#valid? to the strict
matches_current_metadata? check. Every SpecSet.new(...) site in
Definition stops chaining .with_overrides — the LazySpecs already
carry the context.

ruby/rubygems@fc1e8d4d7e

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
complete_platform validates platform-specific candidates returned by
spec.source.specs.search, which are remote specs that do not carry
the override list. Borrow the override list from the LazySpec exemplar
already in scope so platform-variant validation uses the same effective
metadata as the install/resolve path.

Also propagate the overrides onto the synthesized LazySpec built from
platform_spec. Without this, the next complete_platform call could
pick the synthesized variant as its exemplar (it is now in the set
returned by lookup) and fall back to strict matching, dropping
platforms that the user's override would otherwise allow.

ruby/rubygems@205955c5b3

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@pull pull Bot locked and limited conversation to collaborators May 8, 2026
@pull pull Bot added the ⤵️ pull label May 8, 2026
@pull pull Bot merged commit 95ce1c5 into turkdevops:master May 8, 2026
1 of 3 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.

9 participants