diff options
author | Jean Boussier <[email protected]> | 2025-03-13 13:29:37 +0100 |
---|---|---|
committer | Jean Boussier <[email protected]> | 2025-03-14 09:51:57 +0100 |
commit | de48e47ddf78aba02fd9623bc7ce685540a10743 (patch) | |
tree | e4e7d409eb5d8343b85dc2628f5e1c8e7782b2dc | |
parent | dd7deef338d843c8d866ddc279854068b39bfeb9 (diff) |
Invoke `inherited` callbacks before `const_added`
[Misc #21143]
Conceptually this makes sense and is more consistent with using
the `Name = Class.new(Superclass)` alternative method.
However the new class is still named before `inherited` is called.
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/12927
-rw-r--r-- | class.c | 4 | ||||
-rw-r--r-- | spec/ruby/core/class/fixtures/callback_order.rb | 21 | ||||
-rw-r--r-- | spec/ruby/core/class/inherited_spec.rb | 13 | ||||
-rw-r--r-- | spec/ruby/optional/capi/class_spec.rb | 11 | ||||
-rw-r--r-- | spec/ruby/optional/capi/fixtures/class.rb | 10 | ||||
-rw-r--r-- | test/ruby/test_settracefunc.rb | 16 | ||||
-rw-r--r-- | vm_insnhelper.c | 18 |
7 files changed, 72 insertions, 21 deletions
@@ -1004,8 +1004,8 @@ rb_define_class(const char *name, VALUE super) } klass = rb_define_class_id(id, super); rb_vm_register_global_object(klass); - rb_const_set(rb_cObject, id, klass); rb_class_inherited(super, klass); + rb_const_set(rb_cObject, id, klass); return klass; } @@ -1043,8 +1043,8 @@ rb_define_class_id_under_no_pin(VALUE outer, ID id, VALUE super) } klass = rb_define_class_id(id, super); rb_set_class_path_string(klass, outer, rb_id2str(id)); - rb_const_set(outer, id, klass); rb_class_inherited(super, klass); + rb_const_set(outer, id, klass); return klass; } diff --git a/spec/ruby/core/class/fixtures/callback_order.rb b/spec/ruby/core/class/fixtures/callback_order.rb new file mode 100644 index 0000000000..e82e0e6c19 --- /dev/null +++ b/spec/ruby/core/class/fixtures/callback_order.rb @@ -0,0 +1,21 @@ +module CoreClassSpecs + module Callbacks + class Base + def self.inherited(subclass) + subclass.const_set(:INHERITED_NAME, subclass.name) + ORDER << [:inherited, subclass, eval("defined?(#{subclass.name})")] + super + end + end + + ORDER = [] + + def self.const_added(const_name) + ORDER << [:const_added, const_name, eval("defined?(#{const_name})")] + super + end + + class Child < Base + end + end +end diff --git a/spec/ruby/core/class/inherited_spec.rb b/spec/ruby/core/class/inherited_spec.rb index 8ef8bb8c35..3868ba4089 100644 --- a/spec/ruby/core/class/inherited_spec.rb +++ b/spec/ruby/core/class/inherited_spec.rb @@ -1,5 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +require_relative 'fixtures/callback_order' describe "Class.inherited" do @@ -98,4 +99,16 @@ describe "Class.inherited" do -> { Class.new(top) }.should_not raise_error end + it "is invoked after the class is named when using class definition syntax" do + CoreClassSpecs::Callbacks::Child::INHERITED_NAME.should == "CoreClassSpecs::Callbacks::Child" + end + + ruby_version_is "3.5" do # https://bugs.ruby-lang.org/issues/21143 + it "is invoked before `const_added`" do + CoreClassSpecs::Callbacks::ORDER.should == [ + [:inherited, CoreClassSpecs::Callbacks::Child, nil], + [:const_added, :Child, "constant"], + ] + end + end end diff --git a/spec/ruby/optional/capi/class_spec.rb b/spec/ruby/optional/capi/class_spec.rb index a231245ebe..6d53b62b75 100644 --- a/spec/ruby/optional/capi/class_spec.rb +++ b/spec/ruby/optional/capi/class_spec.rb @@ -383,6 +383,17 @@ describe "C-API Class function" do CApiClassSpecs.const_get(cls.name) }.should raise_error(NameError, /wrong constant name/) end + + ruby_version_is "3.5" do + it "calls .inherited before .const_added" do + ScratchPad.record([]) + @s.rb_define_class_id_under(CApiClassSpecs::Callbacks, :Subclass, CApiClassSpecs::Callbacks) + ScratchPad.recorded.should == [ + [:inherited, "CApiClassSpecs::Callbacks::Subclass"], + [:const_added, :Subclass], + ] + end + end end describe "rb_define_class_id_under" do diff --git a/spec/ruby/optional/capi/fixtures/class.rb b/spec/ruby/optional/capi/fixtures/class.rb index b463e3b4c3..a738f2fd0f 100644 --- a/spec/ruby/optional/capi/fixtures/class.rb +++ b/spec/ruby/optional/capi/fixtures/class.rb @@ -101,4 +101,14 @@ class CApiClassSpecs module M end end + + class Callbacks + def self.inherited(child) + ScratchPad << [:inherited, child.name] + end + + def self.const_added(const_name) + ScratchPad << [:const_added, const_name] + end + end end diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb index 55c07abbea..5542ad248a 100644 --- a/test/ruby/test_settracefunc.rb +++ b/test/ruby/test_settracefunc.rb @@ -168,14 +168,14 @@ class TestSetTraceFunc < Test::Unit::TestCase events.shift) assert_equal(["line", 4, __method__, self.class], events.shift) - assert_equal(["c-call", 4, :const_added, Module], - events.shift) - assert_equal(["c-return", 4, :const_added, Module], - events.shift) assert_equal(["c-call", 4, :inherited, Class], events.shift) assert_equal(["c-return", 4, :inherited, Class], events.shift) + assert_equal(["c-call", 4, :const_added, Module], + events.shift) + assert_equal(["c-return", 4, :const_added, Module], + events.shift) assert_equal(["class", 4, nil, nil], events.shift) assert_equal(["line", 5, nil, nil], @@ -411,10 +411,10 @@ class TestSetTraceFunc < Test::Unit::TestCase [["c-return", 2, :add_trace_func, Thread], ["line", 3, __method__, self.class], - ["c-call", 3, :const_added, Module], - ["c-return", 3, :const_added, Module], ["c-call", 3, :inherited, Class], ["c-return", 3, :inherited, Class], + ["c-call", 3, :const_added, Module], + ["c-return", 3, :const_added, Module], ["class", 3, nil, nil], ["line", 4, nil, nil], ["c-call", 4, :method_added, Module], @@ -558,10 +558,10 @@ class TestSetTraceFunc < Test::Unit::TestCase [:line, 5, 'xyzzy', self.class, method, self, :inner, :nothing], [:c_return, 4, "xyzzy", Array, :reverse_each, [1], nil, [1]], [:line, 7, 'xyzzy', self.class, method, self, :outer, :nothing], - [:c_call, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, :nothing], - [:c_return, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, nil], [:c_call, 7, "xyzzy", Class, :inherited, Object, nil, :nothing], [:c_return, 7, "xyzzy", Class, :inherited, Object, nil, nil], + [:c_call, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, :nothing], + [:c_return, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, nil], [:class, 7, "xyzzy", nil, nil, xyzzy.class, nil, :nothing], [:line, 8, "xyzzy", nil, nil, xyzzy.class, nil, :nothing], [:line, 9, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing], diff --git a/vm_insnhelper.c b/vm_insnhelper.c index e7a2728d69..8c0a68ac56 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -5745,29 +5745,25 @@ vm_check_if_module(ID id, VALUE mod) } static VALUE -declare_under(ID id, VALUE cbase, VALUE c) -{ - rb_set_class_path_string(c, cbase, rb_id2str(id)); - rb_const_set(cbase, id, c); - return c; -} - -static VALUE vm_declare_class(ID id, rb_num_t flags, VALUE cbase, VALUE super) { /* new class declaration */ VALUE s = VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) ? super : rb_cObject; - VALUE c = declare_under(id, cbase, rb_define_class_id(id, s)); + VALUE c = rb_define_class_id(id, s); rb_define_alloc_func(c, rb_get_alloc_func(c)); + rb_set_class_path_string(c, cbase, rb_id2str(id)); rb_class_inherited(s, c); + rb_const_set(cbase, id, c); return c; } static VALUE vm_declare_module(ID id, VALUE cbase) { - /* new module declaration */ - return declare_under(id, cbase, rb_module_new()); + VALUE m = rb_module_new(); + rb_set_class_path_string(m, cbase, rb_id2str(id)); + rb_const_set(cbase, id, m); + return m; } NORETURN(static void unmatched_redefinition(const char *type, VALUE cbase, ID id, VALUE old)); |