* internal.h, class.c, eval.c, insns.def: find the appropriate
receiver for super called in instance_eval. If such a receiver is not found, raise NoMethodError. [ruby-dev:39772] [Bug #2402] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36640 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
3dd941b234
commit
9537e8ffe5
@ -1,3 +1,9 @@
|
|||||||
|
Mon Aug 6 15:54:50 2012 Shugo Maeda <shugo@ruby-lang.org>
|
||||||
|
|
||||||
|
* internal.h, class.c, eval.c, insns.def: find the appropriate
|
||||||
|
receiver for super called in instance_eval. If such a receiver is
|
||||||
|
not found, raise NoMethodError. [ruby-dev:39772] [Bug #2402]
|
||||||
|
|
||||||
Mon Aug 6 14:54:38 2012 Shugo Maeda <shugo@ruby-lang.org>
|
Mon Aug 6 14:54:38 2012 Shugo Maeda <shugo@ruby-lang.org>
|
||||||
|
|
||||||
* include/ruby/ruby.h, eval.c, vm_insnhelper.c: fix typo.
|
* include/ruby/ruby.h, eval.c, vm_insnhelper.c: fix typo.
|
||||||
|
1
class.c
1
class.c
@ -58,6 +58,7 @@ class_alloc(VALUE flags, VALUE klass)
|
|||||||
RCLASS_SUPER(obj) = 0;
|
RCLASS_SUPER(obj) = 0;
|
||||||
RCLASS_ORIGIN(obj) = (VALUE)obj;
|
RCLASS_ORIGIN(obj) = (VALUE)obj;
|
||||||
RCLASS_IV_INDEX_TBL(obj) = 0;
|
RCLASS_IV_INDEX_TBL(obj) = 0;
|
||||||
|
RCLASS_REFINED_CLASS(obj) = Qnil;
|
||||||
return (VALUE)obj;
|
return (VALUE)obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
eval.c
2
eval.c
@ -1055,10 +1055,12 @@ rb_overlay_module(NODE *cref, VALUE klass, VALUE module)
|
|||||||
}
|
}
|
||||||
FL_SET(module, RMODULE_IS_OVERLAID);
|
FL_SET(module, RMODULE_IS_OVERLAID);
|
||||||
c = iclass = rb_include_class_new(module, superclass);
|
c = iclass = rb_include_class_new(module, superclass);
|
||||||
|
RCLASS_REFINED_CLASS(c) = klass;
|
||||||
module = RCLASS_SUPER(module);
|
module = RCLASS_SUPER(module);
|
||||||
while (module) {
|
while (module) {
|
||||||
FL_SET(module, RMODULE_IS_OVERLAID);
|
FL_SET(module, RMODULE_IS_OVERLAID);
|
||||||
c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
|
c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
|
||||||
|
RCLASS_REFINED_CLASS(c) = klass;
|
||||||
module = RCLASS_SUPER(module);
|
module = RCLASS_SUPER(module);
|
||||||
}
|
}
|
||||||
rb_hash_aset(cref->nd_omod, klass, iclass);
|
rb_hash_aset(cref->nd_omod, klass, iclass);
|
||||||
|
23
insns.def
23
insns.def
@ -1032,13 +1032,34 @@ invokesuper
|
|||||||
int num = caller_setup_args(th, GET_CFP(), flag,
|
int num = caller_setup_args(th, GET_CFP(), flag,
|
||||||
(int)op_argc, blockiseq, &blockptr);
|
(int)op_argc, blockiseq, &blockptr);
|
||||||
VALUE recv, klass;
|
VALUE recv, klass;
|
||||||
|
rb_control_frame_t *cfp = GET_CFP();
|
||||||
|
rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(th);
|
||||||
ID id;
|
ID id;
|
||||||
const rb_method_entry_t *me;
|
const rb_method_entry_t *me;
|
||||||
rb_iseq_t *ip;
|
rb_iseq_t *ip;
|
||||||
|
|
||||||
flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;
|
flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;
|
||||||
|
|
||||||
recv = GET_SELF();
|
recv = Qundef;
|
||||||
|
while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp)) {
|
||||||
|
if ((VM_EP_LEP_P(cfp->ep) && cfp->iseq &&
|
||||||
|
cfp->iseq->type == ISEQ_TYPE_METHOD) ||
|
||||||
|
(cfp->me && cfp->me->def->type == VM_METHOD_TYPE_BMETHOD)) {
|
||||||
|
recv = cfp->self;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
||||||
|
}
|
||||||
|
if (recv == Qundef) {
|
||||||
|
rb_raise(rb_eNoMethodError, "super called outside of method");
|
||||||
|
}
|
||||||
|
klass = GET_CFP()->klass;
|
||||||
|
if (!NIL_P(RCLASS_REFINED_CLASS(klass))) {
|
||||||
|
klass = RCLASS_REFINED_CLASS(klass);
|
||||||
|
}
|
||||||
|
if (!rb_obj_is_kind_of(recv, klass)) {
|
||||||
|
rb_raise(rb_eNoMethodError, "can't find the method for super, which may be called in an orphan block");
|
||||||
|
}
|
||||||
vm_search_superclass(GET_CFP(), GET_ISEQ(), TOPN(num), &id, &klass);
|
vm_search_superclass(GET_CFP(), GET_ISEQ(), TOPN(num), &id, &klass);
|
||||||
|
|
||||||
ip = GET_ISEQ();
|
ip = GET_ISEQ();
|
||||||
|
@ -28,6 +28,7 @@ struct rb_classext_struct {
|
|||||||
struct st_table *iv_tbl;
|
struct st_table *iv_tbl;
|
||||||
struct st_table *const_tbl;
|
struct st_table *const_tbl;
|
||||||
VALUE origin;
|
VALUE origin;
|
||||||
|
VALUE refined_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef RCLASS_SUPER
|
#undef RCLASS_SUPER
|
||||||
@ -38,6 +39,7 @@ struct rb_classext_struct {
|
|||||||
#define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
|
#define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
|
||||||
#define RCLASS_IV_INDEX_TBL(c) (RCLASS(c)->iv_index_tbl)
|
#define RCLASS_IV_INDEX_TBL(c) (RCLASS(c)->iv_index_tbl)
|
||||||
#define RCLASS_ORIGIN(c) (RCLASS_EXT(c)->origin)
|
#define RCLASS_ORIGIN(c) (RCLASS_EXT(c)->origin)
|
||||||
|
#define RCLASS_REFINED_CLASS(c) (RCLASS_EXT(c)->refined_class)
|
||||||
|
|
||||||
struct vtm; /* defined by timev.h */
|
struct vtm; /* defined by timev.h */
|
||||||
|
|
||||||
|
@ -132,9 +132,9 @@ class TestSuper < Test::Unit::TestCase
|
|||||||
assert_equal("A#tt", a.tt(12), "[ruby-core:3856]")
|
assert_equal("A#tt", a.tt(12), "[ruby-core:3856]")
|
||||||
e = assert_raise(RuntimeError, "[ruby-core:24244]") {
|
e = assert_raise(RuntimeError, "[ruby-core:24244]") {
|
||||||
lambda {
|
lambda {
|
||||||
Class.new do
|
Class.new {
|
||||||
define_method(:a) {super}.call
|
define_method(:a) {super}
|
||||||
end
|
}.new.a
|
||||||
}.call
|
}.call
|
||||||
}
|
}
|
||||||
assert_match(/implicit argument passing of super from method defined by define_method/, e.message)
|
assert_match(/implicit argument passing of super from method defined by define_method/, e.message)
|
||||||
@ -248,4 +248,78 @@ class TestSuper < Test::Unit::TestCase
|
|||||||
assert_equal([:Base, :Override, :A, :Override, :B],
|
assert_equal([:Base, :Override, :A, :Override, :B],
|
||||||
DoubleInclude2::B.new.foo)
|
DoubleInclude2::B.new.foo)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_super_in_instance_eval
|
||||||
|
super_class = Class.new {
|
||||||
|
def foo
|
||||||
|
return [:super, self]
|
||||||
|
end
|
||||||
|
}
|
||||||
|
sub_class = Class.new(super_class) {
|
||||||
|
def foo
|
||||||
|
x = Object.new
|
||||||
|
x.instance_eval do
|
||||||
|
super()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
obj = sub_class.new
|
||||||
|
assert_equal [:super, obj], obj.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_super_in_instance_eval_with_define_method
|
||||||
|
super_class = Class.new {
|
||||||
|
def foo
|
||||||
|
return [:super, self]
|
||||||
|
end
|
||||||
|
}
|
||||||
|
sub_class = Class.new(super_class) {
|
||||||
|
define_method(:foo) do
|
||||||
|
x = Object.new
|
||||||
|
x.instance_eval do
|
||||||
|
super()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
obj = sub_class.new
|
||||||
|
assert_equal [:super, obj], obj.foo
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_super_in_orphan_block
|
||||||
|
super_class = Class.new {
|
||||||
|
def foo
|
||||||
|
return [:super, self]
|
||||||
|
end
|
||||||
|
}
|
||||||
|
sub_class = Class.new(super_class) {
|
||||||
|
def foo
|
||||||
|
x = Object.new
|
||||||
|
lambda { super() }
|
||||||
|
end
|
||||||
|
}
|
||||||
|
obj = sub_class.new
|
||||||
|
assert_raise(NoMethodError) do
|
||||||
|
obj.foo.call
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_super_in_orphan_block_with_instance_eval
|
||||||
|
super_class = Class.new {
|
||||||
|
def foo
|
||||||
|
return [:super, self]
|
||||||
|
end
|
||||||
|
}
|
||||||
|
sub_class = Class.new(super_class) {
|
||||||
|
def foo
|
||||||
|
x = Object.new
|
||||||
|
x.instance_eval do
|
||||||
|
lambda { super() }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
obj = sub_class.new
|
||||||
|
assert_raise(NoMethodError) do
|
||||||
|
obj.foo.call
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user