summaryrefslogtreecommitdiff
path: root/vm_insnhelper.c
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2019-08-21 13:59:36 -0700
committerNobuyoshi Nakada <nobu@ruby-lang.org>2019-12-12 15:50:19 +0900
commit55b7ba368696033f2e89b77cbcd4a05dec97b139 (patch)
tree797c7c459c25bd585cb56a3eb5b159181594ac5e /vm_insnhelper.c
parent1a4a9bdb5da973f8a89e699ce6d0fb1ca21090bd (diff)
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]
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/2717
Diffstat (limited to 'vm_insnhelper.c')
-rw-r--r--vm_insnhelper.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index c8ea3f9b1b..8487886886 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -3126,16 +3126,17 @@ vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *c
}
if (BUILTIN_TYPE(current_defined_class) != T_MODULE &&
- BUILTIN_TYPE(current_defined_class) != T_ICLASS && /* bound UnboundMethod */
!FL_TEST(current_defined_class, RMODULE_INCLUDED_INTO_REFINEMENT) &&
!rb_obj_is_kind_of(recv, current_defined_class)) {
VALUE m = RB_TYPE_P(current_defined_class, T_ICLASS) ?
- RBASIC(current_defined_class)->klass : current_defined_class;
+ RCLASS_INCLUDER(current_defined_class) : current_defined_class;
- rb_raise(rb_eTypeError,
- "self has wrong type to call super in this context: "
- "%"PRIsVALUE" (expected %"PRIsVALUE")",
- rb_obj_class(recv), m);
+ if (m) { /* not bound UnboundMethod */
+ rb_raise(rb_eTypeError,
+ "self has wrong type to call super in this context: "
+ "%"PRIsVALUE" (expected %"PRIsVALUE")",
+ rb_obj_class(recv), m);
+ }
}
if (me->def->type == VM_METHOD_TYPE_BMETHOD && (ci->flag & VM_CALL_ZSUPER)) {