diff options
author | Jeremy Evans <code@jeremyevans.net> | 2019-08-21 13:59:36 -0700 |
---|---|---|
committer | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2019-12-12 15:50:19 +0900 |
commit | 55b7ba368696033f2e89b77cbcd4a05dec97b139 (patch) | |
tree | 797c7c459c25bd585cb56a3eb5b159181594ac5e /test | |
parent | 1a4a9bdb5da973f8a89e699ce6d0fb1ca21090bd (diff) | |
download | ruby-55b7ba368696033f2e89b77cbcd4a05dec97b139.tar.gz |
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]
Diffstat (limited to 'test')
-rw-r--r-- | test/ruby/test_super.rb | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/test/ruby/test_super.rb b/test/ruby/test_super.rb index bb78ab516f..bbfc581500 100644 --- a/test/ruby/test_super.rb +++ b/test/ruby/test_super.rb @@ -307,6 +307,29 @@ class TestSuper < Test::Unit::TestCase end end + def test_super_in_instance_eval_in_module + super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") { + def foo + return [:super, self] + end + } + mod = EnvUtil.labeled_module("Mod\u{30af 30e9 30b9}") { + def foo + x = Object.new + x.instance_eval do + super() + end + end + } + sub_class = EnvUtil.labeled_class("Sub\u{30af 30e9 30b9}", super_class) { + include mod + } + obj = sub_class.new + assert_raise_with_message(TypeError, /Sub\u{30af 30e9 30b9}/) do + obj.foo + end + end + def test_super_in_orphan_block super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") { def foo |