mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Make {Method,UnboundMethod}#super_method handle clone/bind/unbind
This wasn't working previously because the iclass entry wasn't being copied, and without an iclass entry, super_method returns nil. Fixes [Bug #15629]
This commit is contained in:
parent
f9754f0ea0
commit
a91637c516
Notes:
git
2019-12-04 08:35:57 +09:00
2 changed files with 41 additions and 5 deletions
16
proc.c
16
proc.c
|
@ -1686,6 +1686,7 @@ method_unbind(VALUE obj)
|
||||||
&method_data_type, data);
|
&method_data_type, data);
|
||||||
RB_OBJ_WRITE(method, &data->recv, Qundef);
|
RB_OBJ_WRITE(method, &data->recv, Qundef);
|
||||||
RB_OBJ_WRITE(method, &data->klass, orig->klass);
|
RB_OBJ_WRITE(method, &data->klass, orig->klass);
|
||||||
|
RB_OBJ_WRITE(method, &data->iclass, orig->iclass);
|
||||||
RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(orig->me));
|
RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(orig->me));
|
||||||
|
|
||||||
return method;
|
return method;
|
||||||
|
@ -2198,6 +2199,7 @@ method_clone(VALUE self)
|
||||||
CLONESETUP(clone, self);
|
CLONESETUP(clone, self);
|
||||||
RB_OBJ_WRITE(clone, &data->recv, orig->recv);
|
RB_OBJ_WRITE(clone, &data->recv, orig->recv);
|
||||||
RB_OBJ_WRITE(clone, &data->klass, orig->klass);
|
RB_OBJ_WRITE(clone, &data->klass, orig->klass);
|
||||||
|
RB_OBJ_WRITE(clone, &data->iclass, orig->iclass);
|
||||||
RB_OBJ_WRITE(clone, &data->me, rb_method_entry_clone(orig->me));
|
RB_OBJ_WRITE(clone, &data->me, rb_method_entry_clone(orig->me));
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
@ -2345,13 +2347,14 @@ rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE passe
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
convert_umethod_to_method_components(VALUE method, VALUE recv, VALUE *methclass_out, VALUE *klass_out, const rb_method_entry_t **me_out)
|
convert_umethod_to_method_components(VALUE method, VALUE recv, VALUE *methclass_out, VALUE *klass_out, VALUE *iclass_out, const rb_method_entry_t **me_out)
|
||||||
{
|
{
|
||||||
struct METHOD *data;
|
struct METHOD *data;
|
||||||
|
|
||||||
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
|
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
|
||||||
|
|
||||||
VALUE methclass = data->me->owner;
|
VALUE methclass = data->me->owner;
|
||||||
|
VALUE iclass = data->me->defined_class;
|
||||||
VALUE klass = CLASS_OF(recv);
|
VALUE klass = CLASS_OF(recv);
|
||||||
|
|
||||||
if (!RB_TYPE_P(methclass, T_MODULE) &&
|
if (!RB_TYPE_P(methclass, T_MODULE) &&
|
||||||
|
@ -2372,6 +2375,7 @@ convert_umethod_to_method_components(VALUE method, VALUE recv, VALUE *methclass_
|
||||||
VALUE ic = rb_class_search_ancestor(klass, me->owner);
|
VALUE ic = rb_class_search_ancestor(klass, me->owner);
|
||||||
if (ic) {
|
if (ic) {
|
||||||
klass = ic;
|
klass = ic;
|
||||||
|
iclass = ic;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
klass = rb_include_class_new(methclass, klass);
|
klass = rb_include_class_new(methclass, klass);
|
||||||
|
@ -2381,6 +2385,7 @@ convert_umethod_to_method_components(VALUE method, VALUE recv, VALUE *methclass_
|
||||||
|
|
||||||
*methclass_out = methclass;
|
*methclass_out = methclass;
|
||||||
*klass_out = klass;
|
*klass_out = klass;
|
||||||
|
*iclass_out = iclass;
|
||||||
*me_out = me;
|
*me_out = me;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2422,14 +2427,15 @@ convert_umethod_to_method_components(VALUE method, VALUE recv, VALUE *methclass_
|
||||||
static VALUE
|
static VALUE
|
||||||
umethod_bind(VALUE method, VALUE recv)
|
umethod_bind(VALUE method, VALUE recv)
|
||||||
{
|
{
|
||||||
VALUE methclass, klass;
|
VALUE methclass, klass, iclass;
|
||||||
const rb_method_entry_t *me;
|
const rb_method_entry_t *me;
|
||||||
convert_umethod_to_method_components(method, recv, &methclass, &klass, &me);
|
convert_umethod_to_method_components(method, recv, &methclass, &klass, &iclass, &me);
|
||||||
|
|
||||||
struct METHOD *bound;
|
struct METHOD *bound;
|
||||||
method = TypedData_Make_Struct(rb_cMethod, struct METHOD, &method_data_type, bound);
|
method = TypedData_Make_Struct(rb_cMethod, struct METHOD, &method_data_type, bound);
|
||||||
RB_OBJ_WRITE(method, &bound->recv, recv);
|
RB_OBJ_WRITE(method, &bound->recv, recv);
|
||||||
RB_OBJ_WRITE(method, &bound->klass, klass);
|
RB_OBJ_WRITE(method, &bound->klass, klass);
|
||||||
|
RB_OBJ_WRITE(method, &bound->iclass, iclass);
|
||||||
RB_OBJ_WRITE(method, &bound->me, me);
|
RB_OBJ_WRITE(method, &bound->me, me);
|
||||||
|
|
||||||
return method;
|
return method;
|
||||||
|
@ -2451,9 +2457,9 @@ umethod_bind_call(int argc, VALUE *argv, VALUE method)
|
||||||
argc--;
|
argc--;
|
||||||
argv++;
|
argv++;
|
||||||
|
|
||||||
VALUE methclass, klass;
|
VALUE methclass, klass, iclass;
|
||||||
const rb_method_entry_t *me;
|
const rb_method_entry_t *me;
|
||||||
convert_umethod_to_method_components(method, recv, &methclass, &klass, &me);
|
convert_umethod_to_method_components(method, recv, &methclass, &klass, &iclass, &me);
|
||||||
struct METHOD bound = { recv, klass, 0, me };
|
struct METHOD bound = { recv, klass, 0, me };
|
||||||
|
|
||||||
VALUE passed_procval = rb_block_given_p() ? rb_block_proc() : Qnil;
|
VALUE passed_procval = rb_block_given_p() ? rb_block_proc() : Qnil;
|
||||||
|
|
|
@ -991,6 +991,36 @@ class TestMethod < Test::Unit::TestCase
|
||||||
assert_nil(m.super_method)
|
assert_nil(m.super_method)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_super_method_bind_unbind_clone
|
||||||
|
bug15629_m1 = Module.new do
|
||||||
|
def foo; end
|
||||||
|
end
|
||||||
|
|
||||||
|
bug15629_m2 = Module.new do
|
||||||
|
def foo; end
|
||||||
|
end
|
||||||
|
|
||||||
|
bug15629_c = Class.new do
|
||||||
|
include bug15629_m1
|
||||||
|
include bug15629_m2
|
||||||
|
end
|
||||||
|
|
||||||
|
o = bug15629_c.new
|
||||||
|
m = o.method(:foo)
|
||||||
|
sm = m.super_method
|
||||||
|
im = bug15629_c.instance_method(:foo)
|
||||||
|
sim = im.super_method
|
||||||
|
|
||||||
|
assert_equal(sm, m.clone.super_method)
|
||||||
|
assert_equal(sim, m.unbind.super_method)
|
||||||
|
assert_equal(sim, m.unbind.clone.super_method)
|
||||||
|
assert_equal(sim, im.clone.super_method)
|
||||||
|
assert_equal(sm, m.unbind.bind(o).super_method)
|
||||||
|
assert_equal(sm, m.unbind.clone.bind(o).super_method)
|
||||||
|
assert_equal(sm, im.bind(o).super_method)
|
||||||
|
assert_equal(sm, im.clone.bind(o).super_method)
|
||||||
|
end
|
||||||
|
|
||||||
def test_super_method_removed
|
def test_super_method_removed
|
||||||
c1 = Class.new {private def foo; end}
|
c1 = Class.new {private def foo; end}
|
||||||
c2 = Class.new(c1) {public :foo}
|
c2 = Class.new(c1) {public :foo}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue