From d0f60182af9114f6840d993d74f492e483302805 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 20 Dec 2017 10:21:37 +0900 Subject: 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 Barc->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"); -- cgit v1.2.3