diff options
author | nagachika <nagachika@ruby-lang.org> | 2021-03-20 13:29:39 +0900 |
---|---|---|
committer | nagachika <nagachika@ruby-lang.org> | 2021-03-20 13:29:39 +0900 |
commit | c98aa2db60f43e839d7a82897c22b5ceecbed417 (patch) | |
tree | 6a38b18498a0ceccbf90fd758725b8a8b50e9a1a /proc.c | |
parent | 70c3a195f39763dccdf9367d0c9b7e815431a41a (diff) |
merge revision(s) c60aaed1856b2b6f90de0992c34771830019e021: [Backport #17130]
Fix Method#super_method for aliased methods
Previously, Method#super_method looked at the called_id to
determine the method id to use, but that isn't correct for
aliased methods, because the super target depends on the
original method id, not the called_id.
Additionally, aliases can reference methods defined in other
classes and modules, and super lookup needs to start in the
super of the defined class in such cases.
This adds tests for Method#super_method for both types of
aliases, one that uses VM_METHOD_TYPE_ALIAS and another that
does not. Both check that the results for calling super
methods return the expected values.
To find the defined class for alias methods, add an rb_ prefix
to find_defined_class_by_owner in vm_insnhelper.c and make it
non-static, so that it can be called from method_super_method
in proc.c.
This bug was original discovered while researching [Bug #11189].
Fixes [Bug #17130]
---
proc.c | 13 ++++++--
test/ruby/test_method.rb | 80 ++++++++++++++++++++++++++++++++++++++++++++++++
vm_insnhelper.c | 6 ++--
3 files changed, 94 insertions(+), 5 deletions(-)
Diffstat (limited to 'proc.c')
-rw-r--r-- | proc.c | 13 |
1 files changed, 11 insertions, 2 deletions
@@ -3024,6 +3024,8 @@ method_to_proc(VALUE method) return procval; } +extern VALUE rb_find_defined_class_by_owner(VALUE current_class, VALUE target_owner); + /* * call-seq: * meth.super_method -> method @@ -3043,8 +3045,15 @@ method_super_method(VALUE method) TypedData_Get_Struct(method, struct METHOD, &method_data_type, data); iclass = data->iclass; if (!iclass) return Qnil; - super_class = RCLASS_SUPER(RCLASS_ORIGIN(iclass)); - mid = data->me->called_id; + if (data->me->def->type == VM_METHOD_TYPE_ALIAS) { + super_class = RCLASS_SUPER(rb_find_defined_class_by_owner(data->me->defined_class, + data->me->def->body.alias.original_me->owner)); + mid = data->me->def->body.alias.original_me->def->original_id; + } + else { + super_class = RCLASS_SUPER(RCLASS_ORIGIN(iclass)); + mid = data->me->def->original_id; + } if (!super_class) return Qnil; me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(super_class, mid, &iclass); if (!me) return Qnil; |