Project

General

Profile

Bug #11636

super in instance_eval in a method defined in a module is invoked with a wrong receiver

Added by shugo (Shugo Maeda) about 4 years ago. Updated about 15 hours ago.

Status:
Closed
Priority:
Normal
Target version:
-
[ruby-core:71274]

Description

super in instance_eval in a method defined in a module is invoked with a wrong receiver:

class Foo
  def initialize
    @foo = :foo
  end

  def foo
    p [self, @foo]
  end
end

module M
  def foo
    x = Object.new
    x.instance_eval do
      super
    end
  end
end

class Bar < Foo
  include M
end

Bar.new.foo

The output should be [#Foo:..., :foo] or an exception.
Matz prefer the former (https://twitter.com/yukihiro_matz/status/659913844861464576).


Files

instance_eval-module-super-11636.patch (4.93 KB) instance_eval-module-super-11636.patch jeremyevans0 (Jeremy Evans), 08/21/2019 09:12 PM

Related issues

Related to Ruby master - Bug #2402: super in instance_evalClosedActions

Associated revisions

Revision 55b7ba36
Added by jeremyevans (Jeremy Evans) about 15 hours ago

Make super in instance_eval in method in module raise TypeError

This makes behavior the same as super in instance_eval in method
in class. The reason this wasn't implemented before is that
there is a check to determine if the self in the current context
is of the expected class, and a module itself can be included
in multiple classes, so it doesn't have an expected class.

Implementing this requires giving iclasses knowledge of which
class created them, so that super call in the module method
knows the expected class for super calls. This reference
is called includer, and should only be set for iclasses.

Note that the approach Ruby uses in this check is not robust. If
you instance_eval another object of the same class and call super,
instead of an TypeError, you get super called with the
instance_eval receiver instead of the method receiver. Truly
fixing super would require keeping a reference to the super object
(method receiver) in each frame where scope has changed, and using
that instead of current self when calling super.

Fixes [Bug #11636]

History

#1

Updated by shugo (Shugo Maeda) about 4 years ago

  • Related to Bug #2402: super in instance_eval added

Updated by ko1 (Koichi Sasada) about 4 years ago

  • Description updated (diff)

Updated by ko1 (Koichi Sasada) about 4 years ago

I don't touch this behavior because Ruby 2.3 preview 1 was already released.
I try it on Ruby 2.4.

Updated by jeremyevans0 (Jeremy Evans) 4 months ago

This is still a bug in the master branch. Attached is a patch that
fixes it, making the behavior for super in instance_eval in method
in module the same as super in instance_eval in method in class,
raising a TypeError.

This is implemented by keeping a reference to the including class
when creating all iclasses, and using that reference in the check
for expected class in the super check.

Note that the approach Ruby uses in this check is not robust. If
you instance_eval another object of the same class and call super,
instead of a TypeError, you get super called with the
instance_eval receiver instead of the method receiver. Truly
fixing super would require keeping a reference to the super object
(method receiver) in each frame where scope has changed, and using
that instead of current self when calling super.

Updated by matz (Yukihiro Matsumoto) 3 months ago

This bug should be fixed. nobu (Nobuyoshi Nakada) could you review the patch?

Matz.

#6

Updated by jeremyevans (Jeremy Evans) about 15 hours ago

  • Status changed from Assigned to Closed

Applied in changeset git|55b7ba368696033f2e89b77cbcd4a05dec97b139.


Make super in instance_eval in method in module raise TypeError

This makes behavior the same as super in instance_eval in method
in class. The reason this wasn't implemented before is that
there is a check to determine if the self in the current context
is of the expected class, and a module itself can be included
in multiple classes, so it doesn't have an expected class.

Implementing this requires giving iclasses knowledge of which
class created them, so that super call in the module method
knows the expected class for super calls. This reference
is called includer, and should only be set for iclasses.

Note that the approach Ruby uses in this check is not robust. If
you instance_eval another object of the same class and call super,
instead of an TypeError, you get super called with the
instance_eval receiver instead of the method receiver. Truly
fixing super would require keeping a reference to the super object
(method receiver) in each frame where scope has changed, and using
that instead of current self when calling super.

Fixes [Bug #11636]

Also available in: Atom PDF