Skip to content

Implement Ruby 4.0 support#9069

Draft
headius wants to merge 113 commits into10.1-devfrom
ruby-4.0
Draft

Implement Ruby 4.0 support#9069
headius wants to merge 113 commits into10.1-devfrom
ruby-4.0

Conversation

@headius
Copy link
Member

@headius headius commented Nov 11, 2025

This PR will include changes on the ruby-4.0 branch for Ruby 4.0 support.

See #9061 for the feature checklist from CRuby's NEWS and other items.

@headius
Copy link
Member Author

headius commented Nov 11, 2025

Currently still marked as 3.5, since that's what specs and other updates expect currently. Will bump to 4.0 whenever it looks like that's officially propagated through the other libraries and tests.

Several updated gems do not have releases yet:

* RubyGems 4.0.0.dev
* bundler 4.0.0.dev
* stringio 3.1.8.dev
* strscan 3.1.6.dev

And the usual CRuby-specific extension gems remain excluded.
@headius headius changed the title Ruby 4.0 support Implement Ruby 4.0 support Nov 11, 2025
This problem does not seem to be going away, so ignore all missing
extensions on JRuby for now.

See ruby/rubygems#3520
We removed the ability to automatically load extensions from jars
many years ago, but this test remained. It only continued to pass
because some other library loaded the 'json' library which meant
that the tested classes were available. When this same example is
run outside of the test suite, it fails:

```
$ cx jruby-10.0.2.0 ruby -e "require 'uri:file:./lib/ruby/stdlib/json/ext/parser'; p JSON::Ext::Parser"
NameError: uninitialized constant JSON::Ext::Parser
  const_missing at org/jruby/RubyModule.java:4866
         <main> at -e:1
```

Because this functionality no longer exists, I am removing the
test.
A few additional stdlib were added in 4.0 so this archive is now
a bit larger.
Testing all of these features together does not show useful
information when one of them is not pre-required, and basing the
spec name off the list of expected features means it cannot be
reliably tagged for exclusion.

The change here makes this a separate subprocess run for each
provided library, which improves the spec in a few different ways:

* Descriptions are meaningful and can be individually tagged.
  Previously, any change to the list of features would cause
  the spec description to change and error output did not clearly
  indicate which feature failed.
* Failed requires are represented with the string "error" so that
  failure output is useful. Previous logic would just report that
  the subprocess failed.
* Implementation-specific features do not have to be filtered out.
  Both CRuby and JRuby have features at boot that do not exist in
  other implementations, and may add others in the future. The spec
  should not need updating when that happens.

The require check and the loaded feature check are combined into a
single run for efficiency.
This spec was split into a separate spec for each feature to avoid
the description changing and to make the failures more useful.
* Removed SortedSet and related files (gem TBD).
* Removed stdlib .rb stub.
* Fixed inspect output, intersect? with Array, and infinite
  enumerables for new tests.
* Moved @hash variable to a bound Java field.
* Fix inspect output expectations.
* Guard SortedSet tests behind a require, since that collection is
  now in a separate library (knu/sorted_set). These tests probably
  should move to the external library once we work out the details
  (see knu/sorted_set#7)
@headius
Copy link
Member Author

headius commented Nov 15, 2025

Ruby 3.5 was officially promoted to 4.0 last week, so that's what it will be.

Based on code from CRuby by Tomoya Ishida:

ruby/ruby#13680
When the incoming block's signature is important to the iteration
method being called, the previous logic would hide that signature.
The change here propagates it through the CallBlock.
This does not exactly match the new native Set impl, but it passes
specs and tests related to initialize.
This updates some logic related to the new native Set.
Only fails are now related to us not tracking iteration-in-progress
for either Set or Hash.
This may not be exactly the same result as CRuby but it's close
enough and stat is impl-specific.
headius and others added 26 commits January 22, 2026 17:38
Mostly surrounding the handling of `$/`, `$\`, and `$,` with
regards to duping and freezing and assignment of non-nil warnings.
CRuby has for a long time had separate C globals for the default
record separator (`rb_default_rs`) and the configurable record
separator (`rb_rs`), while we only used a single global slot for
both. This led to failures expecting that the configurable version
could be configured using the `-0` flag (as in `-072`) without
affecting e.g. the output of `puts`.

This change may modify behavior in JRuby where we go after the real
global variable (rather than the JRuby global default separator)
but as the `-0` flag and the `$/` and `$-0` globals are being
deprecated, I'm not really worried about it.
This was updated in 2015 but not tested until recently.

See ruby/ruby@f830ace
Now that to_set does not force a size, only endless is rejected.

See ruby/ruby#15173
* All vars if nil is given
* Error if non-nil, non-array given
When I switched to using fetch, I did not notice it also coerces.
Remove the extra coercion here.
I always forget which methods return null and which return UNDEF.
We should unify that some day but for now at least document it.
CRuby has both rb_num2dbl and rb_num_to_dbl, which have slightly
different logic and raise slightly different errors. This patch
matches that to allow both forms of errors to be thrown in the
appropriate places.
CRuby frequently checks if a given VALUE is "immediate", which
in their terms means it has no presence on the heap. We do not
have immediates in JRuby, but we mark these types as such for
optimizations that check for it.

* False is not immediate but True is, so lower that override.
* Float is both in CRuby, but we mark it immediate for fast-path
  logic that checks this.
We are using this to represent all core singleton literals (nil,
false, true), fixnum-ranged integers and all floats and symbols.
This restores immediate status to false.
A Data object should be frozen even if it has no members
This makes the spec pass on Ruby 4.0.0 and earlies as well. This saves
some issues with the next spec sync.
The style `.should.predicate?` is slightly more idiomatic, and seems to
be preferred (see ruby/mspec#80 for a related
discussion).
…thods

Remove Process::Status#& and Process::Status#>>
Add ruby_bug for spec of Data with no members being frozen
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants