From 8eaefd93951143661b1f515a8c9cda12263d2b56 Mon Sep 17 00:00:00 2001 From: qraqras Date: Fri, 28 Nov 2025 09:58:38 +0900 Subject: [PATCH 1/3] [ruby/prism] Fix invalid Ruby code example in ClassNode comment https://github.com/ruby/prism/commit/5b7456c8f6 --- prism/config.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/prism/config.yml b/prism/config.yml index 69a46de628e63c..3acab9f58d5d44 100644 --- a/prism/config.yml +++ b/prism/config.yml @@ -1860,7 +1860,7 @@ nodes: comment: | Represents the location of the `class` keyword. - class Foo end + class Foo; end ^^^^^ - name: constant_path type: node @@ -1899,19 +1899,19 @@ nodes: comment: | Represents the location of the `end` keyword. - class Foo end - ^^^ + class Foo; end + ^^^ - name: name type: constant comment: | The name of the class. - class Foo end # name `:Foo` + class Foo; end # name `:Foo` comment: | Represents a class declaration involving the `class` keyword. - class Foo end - ^^^^^^^^^^^^^ + class Foo; end + ^^^^^^^^^^^^^^ - name: ClassVariableAndWriteNode fields: - name: name From 191bfcb9c505ba3f5771f7ac67d6131aeb6b6837 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Fri, 28 Nov 2025 16:17:06 +0100 Subject: [PATCH 2/3] Define Kernel#instance_variables_to_inspect [Bug #21718] Otherwise objects that don't define it, but define a fairly liberal `method_missing` method will run into errors that are hard to understand: ```ruby class Foo def method_missing(name, ...) name end end p Foo.new.inspect ``` ``` 'Kernel#inspect': wrong argument type Symbol (expected Array) (TypeError) from ../test.rb:7:in '
' ``` --- object.c | 21 ++++++++++++++++--- spec/ruby/core/kernel/inspect_spec.rb | 29 +++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/object.c b/object.c index 097199479e241a..4b73fcefa8a646 100644 --- a/object.c +++ b/object.c @@ -854,14 +854,21 @@ rb_obj_inspect(VALUE obj) { VALUE ivars = rb_check_funcall(obj, id_instance_variables_to_inspect, 0, 0); st_index_t n = 0; - if (UNDEF_P(ivars)) { + if (UNDEF_P(ivars) || NIL_P(ivars)) { n = rb_ivar_count(obj); ivars = Qnil; } - else if (!NIL_P(ivars)) { - Check_Type(ivars, T_ARRAY); + else if (RB_TYPE_P(ivars, T_ARRAY)) { n = RARRAY_LEN(ivars); } + else { + rb_raise( + rb_eTypeError, + "Expected #instance_variables_to_inspect to return an Array or nil, but it returned %"PRIsVALUE, + rb_obj_class(ivars) + ); + } + if (n > 0) { VALUE c = rb_class_name(CLASS_OF(obj)); VALUE args[2] = { @@ -875,6 +882,13 @@ rb_obj_inspect(VALUE obj) } } +/* :nodoc: */ +static VALUE +rb_obj_instance_variables_to_inspect(VALUE obj) +{ + return Qnil; +} + static VALUE class_or_module_required(VALUE c) { @@ -4535,6 +4549,7 @@ InitVM_Object(void) rb_define_method(rb_mKernel, "to_s", rb_any_to_s, 0); rb_define_method(rb_mKernel, "inspect", rb_obj_inspect, 0); + rb_define_private_method(rb_mKernel, "instance_variables_to_inspect", rb_obj_instance_variables_to_inspect, 0); rb_define_method(rb_mKernel, "methods", rb_obj_methods, -1); /* in class.c */ rb_define_method(rb_mKernel, "singleton_methods", rb_obj_singleton_methods, -1); /* in class.c */ rb_define_method(rb_mKernel, "protected_methods", rb_obj_protected_methods, -1); /* in class.c */ diff --git a/spec/ruby/core/kernel/inspect_spec.rb b/spec/ruby/core/kernel/inspect_spec.rb index 6ecf1e1c8c86d1..1fa66cab98a979 100644 --- a/spec/ruby/core/kernel/inspect_spec.rb +++ b/spec/ruby/core/kernel/inspect_spec.rb @@ -57,5 +57,34 @@ class << obj inspected = obj.inspect.sub(/^#" end + + it "displays all instance variables if #instance_variables_to_inspect returns nil" do + obj = Object.new + obj.instance_eval do + @host = "localhost" + @user = "root" + @password = "hunter2" + end + obj.singleton_class.class_eval do + private def instance_variables_to_inspect = nil + end + + inspected = obj.inspect.sub(/^#} + end + + it "raises an error if #instance_variables_to_inspect returns an invalid value" do + obj = Object.new + obj.instance_eval do + @host = "localhost" + @user = "root" + @password = "hunter2" + end + obj.singleton_class.class_eval do + private def instance_variables_to_inspect = {} + end + + ->{ obj.inspect }.should raise_error(TypeError, "Expected #instance_variables_to_inspect to return an Array or nil, but it returned Hash") + end end end From 8c70def42c4596a02d45464d0d694d0c234fb1d7 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 27 Nov 2025 22:57:48 -0800 Subject: [PATCH 3/3] Use ALWAYS_INLINE for vm_getinstancevariable Recently rb_vm_getinstancevariable was introduced exposing this method to ZJIT. On clang specifically this ended up causing the compiler not to inline into vm_exec_core and cause a significant performance regression in optcarrot for the interpreter. Co-authored-by: Luke Gruber --- vm_insnhelper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vm_insnhelper.c b/vm_insnhelper.c index c9913a92bbd748..60e1b647ae5d8d 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1680,6 +1680,7 @@ rb_vm_setclassvariable(const rb_iseq_t *iseq, const rb_control_frame_t *cfp, ID vm_setclassvariable(iseq, cfp, id, val, ic); } +ALWAYS_INLINE(static VALUE vm_getinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, IVC ic)); static inline VALUE vm_getinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, IVC ic) {