diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb index a72d6b34970..7388e0bb31a 100644 --- a/bootstraptest/test_ractor.rb +++ b/bootstraptest/test_ractor.rb @@ -1277,20 +1277,6 @@ assert_equal 'Ractor::IsolationError', %q{ res } -# Class#initialize writes the superclass of an uninitialized class, so it is -# owner-only like any other modification -assert_equal 'can not modify K because it is created by another Ractor', %q{ - K = Class.allocate - - r = Ractor.new { K.send(:initialize, Struct) } - - begin - r.join - rescue Ractor::RemoteError => e - e.cause.message - end -} - # Module#refine writes its refinement tables into the receiver, so the receiver # must be owned too assert_equal 'can not modify M because it is created by another Ractor', %q{ diff --git a/object.c b/object.c index caf6b723462..a14094f8e69 100644 --- a/object.c +++ b/object.c @@ -2200,15 +2200,16 @@ rb_mod_initialize_clone(int argc, VALUE* argv, VALUE clone) * want to treat it like a regular class. */ +/* :nodoc: */ static VALUE -rb_class_initialize(int argc, VALUE *argv, VALUE klass) +rb_class_s_new(int argc, VALUE *argv, VALUE self) { VALUE super; + VALUE klass; - // an uninitialized class is still somebody's, and this writes its superclass - rb_class_modify_check(klass); - if (RCLASS_SUPER(klass) != 0 || klass == rb_cBasicObject) { - rb_raise(rb_eTypeError, "already initialized class"); + // # is an ancestor of every metaclass, so this also receives Foo.singleton_class.new + if (self != rb_cClass) { + rb_raise(rb_eTypeError, "can't create instance of singleton class"); } if (rb_check_arity(argc, 0, 1) == 0) { super = rb_cObject; @@ -2220,6 +2221,7 @@ rb_class_initialize(int argc, VALUE *argv, VALUE klass) rb_raise(rb_eTypeError, "can't inherit uninitialized class"); } } + klass = rb_class_s_alloc(self); rb_class_set_super(klass, super); RCLASS_SET_MAX_IV_COUNT(klass, RCLASS_MAX_IV_COUNT(super)); RCLASS_SET_ALLOCATOR(klass, RCLASS_ALLOCATOR(super)); @@ -2231,6 +2233,23 @@ rb_class_initialize(int argc, VALUE *argv, VALUE klass) return klass; } +/* :nodoc: */ +static VALUE +rb_class_dup(VALUE self) +{ + VALUE dup = rb_class_s_alloc(rb_obj_class(self)); + return rb_obj_dup_setup(self, dup); +} + +/* :nodoc: */ +static VALUE +rb_class_clone(int argc, VALUE *argv, VALUE self) +{ + VALUE kwfreeze = rb_get_freeze_opt(argc, argv); + VALUE clone = rb_class_s_alloc(rb_obj_class(self)); + return rb_obj_clone_setup(self, clone, kwfreeze); +} + /*! \private */ void rb_undefined_alloc(VALUE klass) @@ -4691,11 +4710,13 @@ InitVM_Object(void) rb_define_method(rb_singleton_class(rb_cClass), "allocate", rb_class_alloc, 0); rb_define_method(rb_cClass, "allocate", rb_class_alloc, 0); rb_define_method(rb_cClass, "new", rb_class_new_instance_pass_kw, -1); - rb_define_method(rb_cClass, "initialize", rb_class_initialize, -1); rb_define_method(rb_cClass, "superclass", rb_class_superclass, 0); rb_define_method(rb_cClass, "subclasses", rb_class_subclasses, 0); /* in class.c */ rb_define_method(rb_cClass, "attached_object", rb_class_attached_object, 0); /* in class.c */ - rb_define_alloc_func(rb_cClass, rb_class_s_alloc); + rb_define_singleton_method(rb_cClass, "new", rb_class_s_new, -1); + rb_define_method(rb_cClass, "dup", rb_class_dup, 0); + rb_define_method(rb_cClass, "clone", rb_class_clone, -1); + rb_undef_alloc_func(rb_cClass); rb_undef_method(rb_cClass, "extend_object"); rb_undef_method(rb_cClass, "append_features"); rb_undef_method(rb_cClass, "prepend_features"); diff --git a/spec/ruby/core/class/allocate_spec.rb b/spec/ruby/core/class/allocate_spec.rb index b8950a678ec..b9e8d49758e 100644 --- a/spec/ruby/core/class/allocate_spec.rb +++ b/spec/ruby/core/class/allocate_spec.rb @@ -6,19 +6,6 @@ describe "Class#allocate" do klass.allocate.should.instance_of?(klass) end - it "returns a fully-formed instance of Module" do - klass = Class.allocate - klass.constants.should_not == nil - klass.methods.should_not == nil - end - - it "throws an exception when calling a method on a new instance" do - klass = Class.allocate - -> do - klass.new - end.should.raise(Exception) - end - it "does not call initialize on the new instance" do klass = Class.new do def initialize(*args) @@ -33,9 +20,30 @@ describe "Class#allocate" do klass.allocate.should_not.initialized? end - it "raises TypeError for #superclass" do - -> do - Class.allocate.superclass - end.should.raise(TypeError) + ruby_version_is ""..."4.1" do + it "returns a fully-formed instance of Module" do + klass = Class.allocate + klass.constants.should_not == nil + klass.methods.should_not == nil + end + + it "throws an exception when calling a method on a new instance" do + klass = Class.allocate + -> do + klass.new + end.should.raise(Exception) + end + + it "raises TypeError for #superclass" do + -> do + Class.allocate.superclass + end.should.raise(TypeError) + end + end + + ruby_version_is "4.1" do + it "raises TypeError when called on Class itself" do + -> { Class.allocate }.should.raise(TypeError) + end end end diff --git a/spec/ruby/core/class/initialize_spec.rb b/spec/ruby/core/class/initialize_spec.rb index ab8f0a157e6..cd68644fcb6 100644 --- a/spec/ruby/core/class/initialize_spec.rb +++ b/spec/ruby/core/class/initialize_spec.rb @@ -1,34 +1,45 @@ require_relative '../../spec_helper' -describe "Class#initialize" do - it "is private" do - Class.private_methods(false).should.include?(:initialize) - end - - it "raises a TypeError when called on already initialized classes" do - ->{ - Integer.send :initialize - }.should.raise(TypeError) - - ->{ - Object.send :initialize - }.should.raise(TypeError) - end - - # See [redmine:2601] - it "raises a TypeError when called on BasicObject" do - ->{ - BasicObject.send :initialize - }.should.raise(TypeError) - end - - describe "when given the Class" do - before :each do - @uninitialized = Class.allocate +ruby_version_is ""..."4.1" do + describe "Class#initialize" do + it "is private" do + Class.private_methods(false).should.include?(:initialize) end - it "raises a TypeError" do - ->{@uninitialized.send(:initialize, Class)}.should.raise(TypeError) + it "raises a TypeError when called on already initialized classes" do + ->{ + Integer.send :initialize + }.should.raise(TypeError) + + ->{ + Object.send :initialize + }.should.raise(TypeError) + end + + # See [redmine:2601] + it "raises a TypeError when called on BasicObject" do + ->{ + BasicObject.send :initialize + }.should.raise(TypeError) + end + + describe "when given the Class" do + before :each do + @uninitialized = Class.allocate + end + + it "raises a TypeError" do + ->{@uninitialized.send(:initialize, Class)}.should.raise(TypeError) + end + end + end +end + +ruby_version_is "4.1" do + describe "Class#initialize" do + it "is not defined" do + Class.private_instance_methods(false).should_not.include?(:initialize) + Class.instance_methods(false).should_not.include?(:initialize) end end end diff --git a/test/ruby/test_class.rb b/test/ruby/test_class.rb index ce305536223..a5d715c47a7 100644 --- a/test/ruby/test_class.rb +++ b/test/ruby/test_class.rb @@ -83,12 +83,6 @@ class TestClass < Test::Unit::TestCase assert_nil(Class.new <=> 1) end - def test_class_initialize - assert_raise(TypeError) do - Class.new.instance_eval { initialize } - end - end - def test_instantiate_singleton_class c = class << Object.new; self; end assert_raise(TypeError) { c.new } @@ -317,24 +311,18 @@ class TestClass < Test::Unit::TestCase end def test_uninitialized - assert_raise(TypeError) { Class.allocate.new } - assert_raise(TypeError) { Class.allocate.superclass } - bug6863 = '[ruby-core:47148]' - assert_raise(TypeError, bug6863) { Class.new(Class.allocate) } + assert_raise(TypeError) { Class.allocate } allocator = Class.instance_method(:allocate) + assert_raise(TypeError) { allocator.bind_call(Class) } assert_nothing_raised { allocator.bind(Rational).call } assert_nothing_raised { allocator.bind_call(Rational) } end - def test_uninitialized_with_singleton_class - c = Class.allocate - c.singleton_class - assert_raise(TypeError) { c.new } - end - - def test_uninitialized_dup - assert_raise(TypeError) { Class.allocate.dup.new } + def test_singleton_class_new + assert_raise_with_message(TypeError, /singleton class/) { Integer.singleton_class.new } + assert_raise_with_message(TypeError, /singleton class/) { Class.new.singleton_class.new } + assert_raise_with_message(TypeError, /singleton class/) { Class.singleton_class.new } end def test_nonascii_name diff --git a/tool/rbs_skip_tests b/tool/rbs_skip_tests index 6c19e73c792..5e1d64d6211 100644 --- a/tool/rbs_skip_tests +++ b/tool/rbs_skip_tests @@ -42,6 +42,9 @@ test_TOPDIR(RbConfigSingletonTest) `TOPDIR` is `nil` during CI while RBS type is # Failing because ObjectSpace.count_nodes has been removed test_count_nodes(ObjectSpaceTest) +# Class#initialize has been removed +test_initialize(ClassInstanceTest) + ## Unknown failures # NoMethodError: undefined method 'inspect' for an instance of RBS::UnitTest::Convertibles::ToInt