From 59e389af2893c0fcf8b2cfa008c9a16825bf56ff Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Sat, 3 Dec 2022 05:55:33 +0900 Subject: UnboundMethod only refer defined_class UnboundMethod records caller's class, like `D` or `E` on the following case: ```ruby class C def foo = :foo end class D < C end class E < C end d = D.instance_method(:foo) e = E.instance_method(:foo) ``` But `d` and `e` only refers `C#foo` so that UnboundMethod doesn't record `D` or `E`. This behavior changes the following methods: * `UnboundMethod#inspect` (doesn't show caller's class) * `UnboundMethod#==` (`d == e` for example) fix https://bugs.ruby-lang.org/issues/18798 --- proc.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'proc.c') diff --git a/proc.c b/proc.c index 71b6f1ef80..e4762db494 100644 --- a/proc.c +++ b/proc.c @@ -1724,8 +1724,14 @@ mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE iclass, method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data); - RB_OBJ_WRITE(method, &data->recv, obj); - RB_OBJ_WRITE(method, &data->klass, klass); + if (obj == Qundef) { + RB_OBJ_WRITE(method, &data->recv, Qundef); + RB_OBJ_WRITE(method, &data->klass, Qundef); + } + else { + RB_OBJ_WRITE(method, &data->recv, obj); + RB_OBJ_WRITE(method, &data->klass, klass); + } RB_OBJ_WRITE(method, &data->iclass, iclass); RB_OBJ_WRITE(method, &data->owner, original_me->owner); RB_OBJ_WRITE(method, &data->me, me); @@ -1876,9 +1882,9 @@ method_unbind(VALUE obj) method = TypedData_Make_Struct(rb_cUnboundMethod, struct METHOD, &method_data_type, data); RB_OBJ_WRITE(method, &data->recv, Qundef); - RB_OBJ_WRITE(method, &data->klass, orig->klass); + RB_OBJ_WRITE(method, &data->klass, Qundef); RB_OBJ_WRITE(method, &data->iclass, orig->iclass); - RB_OBJ_WRITE(method, &data->owner, orig->owner); + RB_OBJ_WRITE(method, &data->owner, orig->me->owner); RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(orig->me)); return method; @@ -3139,7 +3145,11 @@ method_inspect(VALUE method) defined_class = RBASIC_CLASS(defined_class); } - if (FL_TEST(mklass, FL_SINGLETON)) { + if (data->recv == Qundef) { + // UnboundMethod + rb_str_buf_append(str, rb_inspect(defined_class)); + } + else if (FL_TEST(mklass, FL_SINGLETON)) { VALUE v = rb_ivar_get(mklass, attached); if (UNDEF_P(data->recv)) { -- cgit v1.2.1