ruby-changes:37657
From: usa <ko1@a...>
Date: Wed, 25 Feb 2015 15:01:41 +0900 (JST)
Subject: [ruby-changes:37657] usa:r49738 (ruby_2_0_0): merge revision(s) 49222,49480,49493: [Backport #10765] [Backport #1010826]
usa 2015-02-25 15:01:25 +0900 (Wed, 25 Feb 2015) New Revision: 49738 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=49738 Log: merge revision(s) 49222,49480,49493: [Backport #10765] [Backport #1010826] 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_0_0/ Modified files: branches/ruby_2_0_0/ChangeLog branches/ruby_2_0_0/class.c branches/ruby_2_0_0/method.h branches/ruby_2_0_0/test/ruby/test_refinement.rb branches/ruby_2_0_0/version.h branches/ruby_2_0_0/vm_method.c Index: ruby_2_0_0/method.h =================================================================== --- ruby_2_0_0/method.h (revision 49737) +++ ruby_2_0_0/method.h (revision 49738) @@ -106,6 +106,9 @@ struct unlinked_method_entry_list_entry https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/method.h#L106 }; #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_0_0/ChangeLog =================================================================== --- ruby_2_0_0/ChangeLog (revision 49737) +++ ruby_2_0_0/ChangeLog (revision 49738) @@ -1,3 +1,21 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/ChangeLog#L1 +Wed Feb 25 14:53:27 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 Feb 25 14:53:27 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 Feb 25 14:41:01 2015 Seiei Higa <hanachin@g...> * vm_method.c (check_definition): Module#public_method_defined?, Index: ruby_2_0_0/vm_method.c =================================================================== --- ruby_2_0_0/vm_method.c (revision 49737) +++ ruby_2_0_0/vm_method.c (revision 49738) @@ -690,10 +690,12 @@ remove_method(VALUE klass, ID mid) https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/vm_method.c#L690 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); @@ -701,6 +703,10 @@ remove_method(VALUE klass, ID mid) https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/vm_method.c#L703 rb_clear_cache_for_undef(klass, mid); 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); } @@ -772,8 +778,7 @@ rb_export_method(VALUE klass, ID name, r https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/vm_method.c#L778 } 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); } @@ -881,8 +886,7 @@ rb_undef(VALUE klass, ID id) https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/vm_method.c#L886 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; @@ -1222,8 +1226,7 @@ rb_alias(VALUE klass, ID name, ID def) https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/vm_method.c#L1226 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_0_0/class.c =================================================================== --- ruby_2_0_0/class.c (revision 49737) +++ ruby_2_0_0/class.c (revision 49738) @@ -986,25 +986,32 @@ ins_methods_pub_i(st_data_t name, st_dat https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/class.c#L986 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; } @@ -1014,7 +1021,7 @@ class_instance_method_list(int argc, VAL https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/class.c#L1021 { VALUE ary; int recur, prepended = 0; - st_table *list; + struct method_entry_arg me_arg; if (argc == 0) { recur = TRUE; @@ -1030,16 +1037,17 @@ class_instance_method_list(int argc, VAL https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/class.c#L1037 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; } @@ -1251,8 +1259,9 @@ rb_obj_public_methods(int argc, VALUE *a https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/class.c#L1259 VALUE rb_obj_singleton_methods(int argc, VALUE *argv, VALUE obj) { - VALUE recur, ary, klass; - st_table *list; + VALUE recur, ary, klass, origin; + struct method_entry_arg me_arg; + st_table *mtbl; if (argc == 0) { recur = Qtrue; @@ -1261,22 +1270,24 @@ rb_obj_singleton_methods(int argc, VALUE https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/class.c#L1270 rb_scan_args(argc, argv, "01", &recur); } klass = CLASS_OF(obj); - list = st_init_numtable(); + origin = RCLASS_ORIGIN(klass); + me_arg.list = st_init_numtable(); + me_arg.recur = RTEST(recur); if (klass && FL_TEST(klass, FL_SINGLETON)) { - if (RCLASS_M_TBL(klass)) - st_foreach(RCLASS_M_TBL(klass), method_entry_i, (st_data_t)list); + if ((mtbl = RCLASS_M_TBL(origin)) != 0) + 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 (RCLASS_M_TBL(klass)) - st_foreach(RCLASS_M_TBL(klass), method_entry_i, (st_data_t)list); + if (klass != origin && (mtbl = RCLASS_M_TBL(klass)) != 0) + 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_0_0/version.h =================================================================== --- ruby_2_0_0/version.h (revision 49737) +++ ruby_2_0_0/version.h (revision 49738) @@ -1,6 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/version.h#L1 #define RUBY_VERSION "2.0.0" #define RUBY_RELEASE_DATE "2015-02-25" -#define RUBY_PATCHLEVEL 640 +#define RUBY_PATCHLEVEL 641 #define RUBY_RELEASE_YEAR 2015 #define RUBY_RELEASE_MONTH 2 Index: ruby_2_0_0/test/ruby/test_refinement.rb =================================================================== --- ruby_2_0_0/test/ruby/test_refinement.rb (revision 49737) +++ ruby_2_0_0/test/ruby/test_refinement.rb (revision 49738) @@ -1120,6 +1120,85 @@ class TestRefinement < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/ruby_2_0_0/test/ruby/test_refinement.rb#L1120 end; end + def test_remove_refined_method + assert_separately([], <<-"end;") + $VERBOSE = nil + 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;") + $VERBOSE = nil + 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_0_0 ___________________________________________________________________ Modified: svn:mergeinfo Merged /trunk:r49222,49480,49493 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/