ruby-changes:37911
From: nagachika <ko1@a...>
Date: Wed, 18 Mar 2015 01:12:49 +0900 (JST)
Subject: [ruby-changes:37911] nagachika:r49992 (ruby_2_1): merge revision(s) r49222, r49480, r49493: [Backport #10765]
nagachika 2015-03-18 01:12:28 +0900 (Wed, 18 Mar 2015) New Revision: 49992 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=49992 Log: merge revision(s) r49222,r49480,r49493: [Backport #10765] method.h: UNDEFINED_REFINED_METHOD_P * method.h (UNDEFINED_REFINED_METHOD_P): macro to tell if refined original method is defined. * vm_method.c (remove_method): When remove refined method, raise a NameError if the method is not defined in refined class. But if the method is defined in refined class, it should keep refined method and remove original method. Patch by Seiei Higa. [ruby-core:67722] [Bug #10765] * class.c (method_entry_i, class_instance_method_list, rb_obj_singleton_methods): should not include methods of superclasses if recur is false. [ruby-dev:48854] [Bug #10826] Modified directories: branches/ruby_2_1/ Modified files: branches/ruby_2_1/ChangeLog branches/ruby_2_1/class.c branches/ruby_2_1/method.h branches/ruby_2_1/test/ruby/test_refinement.rb branches/ruby_2_1/version.h branches/ruby_2_1/vm_method.c Index: ruby_2_1/method.h =================================================================== --- ruby_2_1/method.h (revision 49991) +++ ruby_2_1/method.h (revision 49992) @@ -108,6 +108,9 @@ struct unlinked_method_entry_list_entry https://github.com/ruby/ruby/blob/trunk/ruby_2_1/method.h#L108 }; #define UNDEFINED_METHOD_ENTRY_P(me) (!(me) || !(me)->def || (me)->def->type == VM_METHOD_TYPE_UNDEF) +#define UNDEFINED_REFINED_METHOD_P(def) \ + ((def)->type == VM_METHOD_TYPE_REFINED && \ + UNDEFINED_METHOD_ENTRY_P((def)->body.orig_me)) void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex); rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_flag_t noex); Index: ruby_2_1/ChangeLog =================================================================== --- ruby_2_1/ChangeLog (revision 49991) +++ ruby_2_1/ChangeLog (revision 49992) @@ -1,3 +1,21 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_1/ChangeLog#L1 +Wed Mar 18 00:58:43 2015 Shugo Maeda <shugo@r...> + + * class.c (method_entry_i, class_instance_method_list, + rb_obj_singleton_methods): should not include methods of + superclasses if recur is false. [ruby-dev:48854] [Bug #10826] + +Wed Mar 18 00:58:43 2015 Shugo Maeda <shugo@r...> + + * vm_method.c (remove_method): When remove refined + method, raise a NameError if the method is not + defined in refined class. + + But if the method is defined in refined class, + it should keep refined method and remove original + method. + + Patch by Seiei Higa. [ruby-core:67722] [Bug #10765] + Wed Mar 18 00:32:08 2015 Seiei Higa <hanachin@g...> * vm_method.c (check_definition): Module#public_method_defined?, Index: ruby_2_1/vm_method.c =================================================================== --- ruby_2_1/vm_method.c (revision 49991) +++ ruby_2_1/vm_method.c (revision 49992) @@ -732,10 +732,12 @@ remove_method(VALUE klass, ID mid) https://github.com/ruby/ruby/blob/trunk/ruby_2_1/vm_method.c#L732 if (!st_lookup(RCLASS_M_TBL(klass), mid, &data) || !(me = (rb_method_entry_t *)data) || - (!me->def || me->def->type == VM_METHOD_TYPE_UNDEF)) { + (!me->def || me->def->type == VM_METHOD_TYPE_UNDEF) || + UNDEFINED_REFINED_METHOD_P(me->def)) { rb_name_error(mid, "method `%s' not defined in %s", rb_id2name(mid), rb_class2name(klass)); } + key = (st_data_t)mid; st_delete(RCLASS_M_TBL(klass), &key, &data); @@ -743,6 +745,10 @@ remove_method(VALUE klass, ID mid) https://github.com/ruby/ruby/blob/trunk/ruby_2_1/vm_method.c#L745 rb_clear_method_cache_by_class(klass); rb_unlink_method_entry(me); + if (me->def->type == VM_METHOD_TYPE_REFINED) { + rb_add_refined_method_entry(klass, mid); + } + CALL_METHOD_HOOK(self, removed, mid); } @@ -812,8 +818,7 @@ rb_export_method(VALUE klass, ID name, r https://github.com/ruby/ruby/blob/trunk/ruby_2_1/vm_method.c#L818 } if (UNDEFINED_METHOD_ENTRY_P(me) || - (me->def->type == VM_METHOD_TYPE_REFINED && - UNDEFINED_METHOD_ENTRY_P(me->def->body.orig_me))) { + UNDEFINED_REFINED_METHOD_P(me->def)) { rb_print_undef(klass, name, 0); } @@ -912,8 +917,7 @@ rb_undef(VALUE klass, ID id) https://github.com/ruby/ruby/blob/trunk/ruby_2_1/vm_method.c#L917 me = search_method(klass, id, 0); if (UNDEFINED_METHOD_ENTRY_P(me) || - (me->def->type == VM_METHOD_TYPE_REFINED && - UNDEFINED_METHOD_ENTRY_P(me->def->body.orig_me))) { + UNDEFINED_REFINED_METHOD_P(me->def)) { const char *s0 = " class"; VALUE c = klass; @@ -1260,8 +1264,7 @@ rb_alias(VALUE klass, ID name, ID def) https://github.com/ruby/ruby/blob/trunk/ruby_2_1/vm_method.c#L1264 orig_me = search_method(klass, def, &defined_class); if (UNDEFINED_METHOD_ENTRY_P(orig_me) || - (orig_me->def->type == VM_METHOD_TYPE_REFINED && - UNDEFINED_METHOD_ENTRY_P(orig_me->def->body.orig_me))) { + UNDEFINED_REFINED_METHOD_P(orig_me->def)) { if ((!RB_TYPE_P(klass, T_MODULE)) || (orig_me = search_method(rb_cObject, def, 0), UNDEFINED_METHOD_ENTRY_P(orig_me))) { Index: ruby_2_1/class.c =================================================================== --- ruby_2_1/class.c (revision 49991) +++ ruby_2_1/class.c (revision 49992) @@ -1116,25 +1116,32 @@ ins_methods_pub_i(st_data_t name, st_dat https://github.com/ruby/ruby/blob/trunk/ruby_2_1/class.c#L1116 return ins_methods_push((ID)name, (long)type, (VALUE)ary, NOEX_PUBLIC); } +struct method_entry_arg { + st_table *list; + int recur; +}; + static int method_entry_i(st_data_t key, st_data_t value, st_data_t data) { const rb_method_entry_t *me = (const rb_method_entry_t *)value; - st_table *list = (st_table *)data; + struct method_entry_arg *arg = (struct method_entry_arg *)data; long type; if (me && me->def->type == VM_METHOD_TYPE_REFINED) { + VALUE klass = me->klass; me = rb_resolve_refined_method(Qnil, me, NULL); if (!me) return ST_CONTINUE; + if (!arg->recur && me->klass != klass) return ST_CONTINUE; } - if (!st_lookup(list, key, 0)) { + if (!st_lookup(arg->list, key, 0)) { if (UNDEFINED_METHOD_ENTRY_P(me)) { type = -1; /* none */ } else { type = VISI(me->flag); } - st_add_direct(list, key, type); + st_add_direct(arg->list, key, type); } return ST_CONTINUE; } @@ -1144,7 +1151,7 @@ class_instance_method_list(int argc, VAL https://github.com/ruby/ruby/blob/trunk/ruby_2_1/class.c#L1151 { VALUE ary; int recur, prepended = 0; - st_table *list; + struct method_entry_arg me_arg; if (argc == 0) { recur = TRUE; @@ -1160,16 +1167,17 @@ class_instance_method_list(int argc, VAL https://github.com/ruby/ruby/blob/trunk/ruby_2_1/class.c#L1167 prepended = 1; } - list = st_init_numtable(); + me_arg.list = st_init_numtable(); + me_arg.recur = recur; for (; mod; mod = RCLASS_SUPER(mod)) { - if (RCLASS_M_TBL(mod)) st_foreach(RCLASS_M_TBL(mod), method_entry_i, (st_data_t)list); + if (RCLASS_M_TBL(mod)) st_foreach(RCLASS_M_TBL(mod), method_entry_i, (st_data_t)&me_arg); if (BUILTIN_TYPE(mod) == T_ICLASS && !prepended) continue; if (obj && FL_TEST(mod, FL_SINGLETON)) continue; if (!recur) break; } ary = rb_ary_new(); - st_foreach(list, func, ary); - st_free_table(list); + st_foreach(me_arg.list, func, ary); + st_free_table(me_arg.list); return ary; } @@ -1391,7 +1399,8 @@ VALUE https://github.com/ruby/ruby/blob/trunk/ruby_2_1/class.c#L1399 rb_obj_singleton_methods(int argc, VALUE *argv, VALUE obj) { VALUE recur, ary, klass, origin; - st_table *list, *mtbl; + struct method_entry_arg me_arg; + st_table *mtbl; if (argc == 0) { recur = Qtrue; @@ -1401,22 +1410,23 @@ rb_obj_singleton_methods(int argc, VALUE https://github.com/ruby/ruby/blob/trunk/ruby_2_1/class.c#L1410 } klass = CLASS_OF(obj); origin = RCLASS_ORIGIN(klass); - list = st_init_numtable(); + me_arg.list = st_init_numtable(); + me_arg.recur = recur; if (klass && FL_TEST(klass, FL_SINGLETON)) { if ((mtbl = RCLASS_M_TBL(origin)) != 0) - st_foreach(mtbl, method_entry_i, (st_data_t)list); + st_foreach(mtbl, method_entry_i, (st_data_t)&me_arg); klass = RCLASS_SUPER(klass); } if (RTEST(recur)) { while (klass && (FL_TEST(klass, FL_SINGLETON) || RB_TYPE_P(klass, T_ICLASS))) { if (klass != origin && (mtbl = RCLASS_M_TBL(klass)) != 0) - st_foreach(mtbl, method_entry_i, (st_data_t)list); + st_foreach(mtbl, method_entry_i, (st_data_t)&me_arg); klass = RCLASS_SUPER(klass); } } ary = rb_ary_new(); - st_foreach(list, ins_methods_i, ary); - st_free_table(list); + st_foreach(me_arg.list, ins_methods_i, ary); + st_free_table(me_arg.list); return ary; } Index: ruby_2_1/version.h =================================================================== --- ruby_2_1/version.h (revision 49991) +++ ruby_2_1/version.h (revision 49992) @@ -1,6 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_1/version.h#L1 #define RUBY_VERSION "2.1.5" #define RUBY_RELEASE_DATE "2015-03-18" -#define RUBY_PATCHLEVEL 313 +#define RUBY_PATCHLEVEL 314 #define RUBY_RELEASE_YEAR 2015 #define RUBY_RELEASE_MONTH 3 Index: ruby_2_1/test/ruby/test_refinement.rb =================================================================== --- ruby_2_1/test/ruby/test_refinement.rb (revision 49991) +++ ruby_2_1/test/ruby/test_refinement.rb (revision 49992) @@ -1281,6 +1281,83 @@ class TestRefinement < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/ruby_2_1/test/ruby/test_refinement.rb#L1281 end; end + def test_remove_refined_method + assert_separately([], <<-"end;") + bug10765 = '[ruby-core:67722] [Bug #10765]' + + class C + def foo + "C#foo" + end + end + + module RefinementBug + refine C do + def foo + "RefinementBug#foo" + end + end + end + + using RefinementBug + + class C + remove_method :foo + end + + assert_equal("RefinementBug#foo", C.new.foo, bug10765) + end; + end + + def test_remove_undefined_refined_method + assert_separately([], <<-"end;") + bug10765 = '[ruby-core:67722] [Bug #10765]' + + class C + end + + module RefinementBug + refine C do + def foo + end + end + end + + using RefinementBug + + assert_raise(NameError, bug10765) { + class C + remove_method :foo + end + } + end; + end + + module NotIncludeSuperclassMethod + class X + def foo + end + end + + class Y < X + end + + module Bar + refine Y do + def foo + end + end + end + end + + def test_instance_methods_not_include_superclass_method + bug10826 = '[ruby-dev:48854] [Bug #10826]' + assert_not_include(NotIncludeSuperclassMethod::Y.instance_methods(false), + :foo, bug10826) + assert_include(NotIncludeSuperclassMethod::Y.instance_methods(true), + :foo, bug10826) + end + private def eval_using(mod, s) Property changes on: ruby_2_1 ___________________________________________________________________ Modified: svn:mergeinfo Merged /trunk:r49222,49480,49493 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/