Skip to content

Ruby 4.0 incompatibility with subclasses of Set due to new Set::SubclassCompatible layer #2516

@davidcelis

Description

@davidcelis

Ruby 4.0 introduced a compatibility layer for classes that inherit from Set, the Set::SubclassCompatible module which currently breaks Sorbet's static checks against Tapioca-generated RBI files: https://docs.ruby-lang.org/en/master/Set.html#class-set-inheriting-from-set

As of Ruby 4.0, when a class inherits from Set, Ruby dynamically requires a file in its standard library that defines the Set::SubclassCompatible constant, which seems to mean that it's otherwise unavailable during static checks: https://github.com/ruby/ruby/blob/master/set.c#L422-L432

static VALUE
set_s_inherited(VALUE klass, VALUE subclass)
{
    if (klass == rb_cSet) {
        // When subclassing directly from Set, include the compatibility layer
        rb_require("set/subclass_compatible.rb");
        VALUE subclass_compatible = rb_const_get(klass, id_subclass_compatible);
        rb_include_module(subclass, subclass_compatible);
        rb_extend_object(subclass, rb_const_get(subclass_compatible, id_class_methods));
    }
    return Qnil;
}

We discovered this when trying to upgrade our application to Ruby 4. One of our gem dependencies defines a class that inherits from Set, and running tapioca gem results in an RBI file for that gem that triggers errors when running srb tc:

sorbet/rbi/gems/block-kit@1.0.7.rbi:4180: Unable to resolve constant SubclassCompatible https://srb.help/5002
    4180 |  include ::Set::SubclassCompatible
                    ^^^^^^^^^^^^^^^^^^^^^^^^^
  Did you mean Comparable? Use -a to autocorrect
    sorbet/rbi/gems/block-kit@1.0.7.rbi:4180: Replace with Comparable
    4180 |  include ::Set::SubclassCompatible
                    ^^^^^^^^^^^^^^^^^^^^^^^^^
    https://github.com/sorbet/sorbet/tree/3558afcc707c2790d81c4ffd54243a55c4435a89/rbi/core/comparable.rbi#L40: Comparable defined here
    40 |module Comparable
        ^^^^^^^^^^^^^^^^^

sorbet/rbi/gems/block-kit@1.0.7.rbi:4181: Unable to resolve constant SubclassCompatible https://srb.help/5002
    4181 |  extend ::Set::SubclassCompatible::ClassMethods
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
  Did you mean Comparable? Use -a to autocorrect
    sorbet/rbi/gems/block-kit@1.0.7.rbi:4181: Replace with Comparable
    4181 |  extend ::Set::SubclassCompatible::ClassMethods
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
    https://github.com/sorbet/sorbet/tree/3558afcc707c2790d81c4ffd54243a55c4435a89/rbi/core/comparable.rbi#L40: Comparable defined here
    40 |module Comparable
        ^^^^^^^^^^^^^^^^^

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions