Project

General

Profile

Actions

Bug #17130

closed

Method#super_method is broken for aliased methods

Added by jeremyevans0 (Jeremy Evans) over 3 years ago. Updated almost 2 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 2.8.0dev (2020-08-25T21:09:31Z master a84a2e872f) [x86_64-openbsd6.7]
[ruby-core:99709]

Description

Method#super_method currently does not work correctly for aliased methods. Here's a simple example:

class A
  def m1; p :A_m1 end
  def m2; p :A_m2 end
end
class B < A
  def m1; p :B_m1; super end
  alias m2 m1
end

B.new.m2
puts

m = B.new.method(:m2)
m.call

puts
m.super_method.call

Current Output:

:B_m1
:A_m1

:B_m1
:A_m1

:A_m2

You can see from this example that normal super lookup for B#m2 is A#m1, as B#m2 is an alias of B#m1 and super lookup follows the original method name, not the aliased name. However, the super_method call returns a Method instance for A#m2 instead of A#m1.

There is another issue with aliases and that is when the method being aliased is from another module or class. In this case, super lookup needs to start at the super class of the defined class of the method being aliased. See https://bugs.ruby-lang.org/issues/11189#note-3 for an example of that issue.

I have a fix that handles both of these cases that I'll submit shortly via a pull request.

Actions #2

Updated by jeremyevans (Jeremy Evans) over 3 years ago

  • Status changed from Open to Closed

Applied in changeset git|c60aaed1856b2b6f90de0992c34771830019e021.


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]

Actions #3

Updated by nagachika (Tomoyuki Chikanaga) over 3 years ago

  • Backport changed from 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN to 2.5: UNKNOWN, 2.6: REQUIRED, 2.7: REQUIRED

Updated by nagachika (Tomoyuki Chikanaga) about 3 years ago

  • Backport changed from 2.5: UNKNOWN, 2.6: REQUIRED, 2.7: REQUIRED to 2.5: UNKNOWN, 2.6: REQUIRED, 2.7: DONE

ruby_2_7 c98aa2db60f43e839d7a82897c22b5ceecbed417 merged revision(s) c60aaed1856b2b6f90de0992c34771830019e021.

Updated by usa (Usaku NAKAMURA) almost 3 years ago

  • Backport changed from 2.5: UNKNOWN, 2.6: REQUIRED, 2.7: DONE to 2.5: UNKNOWN, 2.6: DONE, 2.7: DONE

backported into ruby_2_6 at r67933

Updated by Dan0042 (Daniel DeLorme) almost 2 years ago

It looks to me like super_method is still broken for aliased methods.

class A
  def foo; end
end
class B < A
  alias foo2 foo
end
p B.instance_method(:foo2).super_method #=> #<UnboundMethod: A#foo>

I believe that here B.instance_method(:foo2).super_method should be nil, as it was in ruby <= 2.5

I'm not sure if this is a different bug, or a side effect of the above patch.

Updated by Eregon (Benoit Daloze) almost 2 years ago

@Dan0042 (Daniel DeLorme) Indeed, here is another example, with an actual super call to prove what it calls:

class P
  def foo; :P; end
end
class A < P
  def foo; super; end
end
class B < A
  alias foo2 foo
end

p B.new.foo2 # :P

p A.instance_method(:foo).super_method # #<UnboundMethod: P#foo() sup.rb:2>
p B.instance_method(:foo2).super_method # #<UnboundMethod: A#foo() sup.rb:5>

It should be P#foo() for both .super_method.
TruffleRuby already behaves correctly here:

:P
#<UnboundMethod: P#foo() sup.rb:2>
#<UnboundMethod: P#foo() sup.rb:2>
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0