summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2017-12-20 10:21:37 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2017-12-20 10:34:54 +0900
commitd0f60182af9114f6840d993d74f492e483302805 (patch)
tree1ec990607833219fc2ea735c64408b56b2e39ec3 /src
parentd9049c10fa922e6978257eaf9fa777b4f844777d (diff)
downloadmruby-d0f60182af9114f6840d993d74f492e483302805.tar.gz
mruby-d0f60182af9114f6840d993d74f492e483302805.zip
The superclass info should be taken from `TARGET_CLASS(ci->proc).
Not from `ci->target_class` that may be switched using `class_eval` etc. fix #3899, fix #3906 We found out there is a mruby specific limitation that `super` may be screwed up when a method is defined in a module and `super` is called in the block with the target class switched (for example, `super` in `class_eval` block). Now we raise `RuntimeError` for such cases. The following code works in CRuby but not in mruby. ``` module M def foo "aaa".singleton_class.class_eval{super 2} end end class Foo def foo(*); end end class Bar<Foo include M end Bar.new.foo ```
Diffstat (limited to 'src')
-rw-r--r--src/vm.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/src/vm.c b/src/vm.c
index 353924477..885888985 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -1589,14 +1589,23 @@ RETRY_TRY_BLOCK:
mrb_callinfo *ci = mrb->c->ci;
mrb_value recv, blk;
mrb_sym mid = ci->mid;
+ struct RClass* target_class = MRB_PROC_TARGET_CLASS(ci->proc);
mrb_assert(bidx < ci->nregs);
- if (mid == 0 || !ci->target_class) {
+ if (mid == 0 || !target_class) {
mrb_value exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
mrb_exc_set(mrb, exc);
goto L_RAISE;
}
+ if (target_class->tt == MRB_TT_MODULE) {
+ target_class = ci->target_class;
+ if (target_class->tt != MRB_TT_ICLASS) {
+ mrb_value exc = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "superclass info lost [mruby limitations]");
+ mrb_exc_set(mrb, exc);
+ goto L_RAISE;
+ }
+ }
recv = regs[0];
blk = regs[bidx];
if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) {
@@ -1606,7 +1615,7 @@ RETRY_TRY_BLOCK:
regs[bidx] = blk;
ci = mrb->c->ci;
}
- c = ci->target_class->super;
+ c = target_class->super;
m = mrb_method_search_vm(mrb, &c, mid);
if (MRB_METHOD_UNDEF_P(m)) {
mrb_sym missing = mrb_intern_lit(mrb, "method_missing");