[前][次][番号順一覧][スレッド一覧]

ruby-changes:24215

From: nobu <ko1@a...>
Date: Mon, 2 Jul 2012 17:06:48 +0900 (JST)
Subject: [ruby-changes:24215] nobu:r36266 (trunk): prepend: fix mixing with include

nobu	2012-07-02 17:06:37 +0900 (Mon, 02 Jul 2012)

  New Revision: 36266

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=36266

  Log:
    prepend: fix mixing with include
    
    * class.c (rb_include_module): include modules after the origin.
    * class.c (include_modules_at): skip prepended modules.
    * class.c (rb_prepend_module): now basic.klass in ICLASS refers the
      old original class/module.  [ruby-dev:45868][Bug #6662]
    * class.c (rb_mod_ancestors): ditto.
    * vm_method.c (search_method): search method entry from the origin
      iclass.

  Modified files:
    trunk/ChangeLog
    trunk/class.c
    trunk/test/ruby/test_module.rb
    trunk/vm_method.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 36265)
+++ ChangeLog	(revision 36266)
@@ -1,3 +1,17 @@
+Mon Jul  2 17:06:32 2012  Nobuyoshi Nakada  <nobu@r...>
+
+	* class.c (rb_include_module): include modules after the origin.
+
+	* class.c (include_modules_at): skip prepended modules.
+
+	* class.c (rb_prepend_module): now basic.klass in ICLASS refers the
+	  old original class/module.  [ruby-dev:45868][Bug #6662]
+
+	* class.c (rb_mod_ancestors): ditto.
+
+	* vm_method.c (search_method): search method entry from the origin
+	  iclass.
+
 Mon Jul  2 05:54:58 2012  Tadayoshi Funaba  <tadf@d...>
 
 	* ext/date/date_core.c: [ruby-core:46058].
Index: vm_method.c
===================================================================
--- vm_method.c	(revision 36265)
+++ vm_method.c	(revision 36266)
@@ -387,15 +387,13 @@
 search_method(VALUE klass, ID id)
 {
     st_data_t body;
-    if (!klass) {
-	return 0;
-    }
 
-    while (!RCLASS_M_TBL(klass) || !st_lookup(RCLASS_M_TBL(klass), id, &body)) {
-	klass = RCLASS_SUPER(klass);
-	if (!klass) {
-	    return 0;
+    for (body = 0; klass; klass = RCLASS_SUPER(klass)) {
+	st_table *m_tbl = RCLASS_M_TBL(klass);
+	if (!m_tbl) {
+	    m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(RBASIC(klass)->klass));
 	}
+	if (st_lookup(m_tbl, id, &body)) break;
     }
 
     return (rb_method_entry_t *)body;
Index: class.c
===================================================================
--- class.c	(revision 36265)
+++ class.c	(revision 36266)
@@ -668,7 +668,9 @@
 
     OBJ_INFECT(klass, module);
 
-    changed = include_modules_at(klass, klass, module);
+    changed = include_modules_at(klass, RCLASS_ORIGIN(klass), module);
+    if (changed < 0)
+	rb_raise(rb_eArgError, "cyclic include detected");
     if (changed) rb_clear_cache();
 }
 
@@ -681,8 +683,10 @@
     while (module) {
 	int superclass_seen = FALSE;
 
-	if (RCLASS_M_TBL(klass) == RCLASS_M_TBL(module))
-	    rb_raise(rb_eArgError, "cyclic include detected");
+	if (RCLASS_ORIGIN(module) != module)
+	    goto skip;
+	if (RCLASS_M_TBL(klass) && RCLASS_M_TBL(klass) == RCLASS_M_TBL(module))
+	    return -1;
 	/* ignore if the module included already in superclasses */
 	for (p = RCLASS_SUPER(klass); p; p = RCLASS_SUPER(p)) {
 	    switch (BUILTIN_TYPE(p)) {
@@ -699,8 +703,6 @@
 		break;
 	    }
 	}
-	if (c == klass)
-	    c = RCLASS_ORIGIN(klass);
 	c = RCLASS_SUPER(c) = include_class_new(module, RCLASS_SUPER(c));
 	if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries)
 	    changed = 1;
@@ -714,7 +716,7 @@
 void
 rb_prepend_module(VALUE klass, VALUE module)
 {
-    VALUE p, c, origin;
+    VALUE origin;
     int changed = 0;
 
     rb_frozen_class_p(klass);
@@ -725,32 +727,19 @@
     Check_Type(module, T_MODULE);
 
     OBJ_INFECT(klass, module);
-    c = RCLASS_SUPER(klass);
-    if (RCLASS_M_TBL(klass) == RCLASS_M_TBL(module))
-	rb_raise(rb_eArgError, "cyclic prepend detected");
-    for (p = c; p; p = RCLASS_SUPER(p)) {
-	if (BUILTIN_TYPE(p) == T_ICLASS) {
-	    if (RCLASS_M_TBL(p) == RCLASS_M_TBL(module)) {
-		rb_raise(rb_eArgError, "already prepended module");
-	    }
-	}
-    }
+
     origin = RCLASS_ORIGIN(klass);
     if (origin == klass) {
-	origin = class_alloc(T_ICLASS, rb_cClass);
+	origin = class_alloc(T_ICLASS, klass);
 	RCLASS_SUPER(origin) = RCLASS_SUPER(klass);
 	RCLASS_SUPER(klass) = origin;
 	RCLASS_ORIGIN(klass) = origin;
 	RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass);
 	RCLASS_M_TBL(klass) = 0;
-	c = origin;
     }
-    RCLASS_SUPER(klass) = include_class_new(module, c);
-    if (RCLASS_SUPER(module)) {
-	changed = include_modules_at(klass, RCLASS_SUPER(klass), RCLASS_SUPER(module));
-    }
-    if (!changed)
-	changed = RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries;
+    changed = include_modules_at(klass, klass, module);
+    if (changed < 0)
+	rb_raise(rb_eArgError, "cyclic prepend detected");
     if (changed) rb_clear_cache();
 }
 
@@ -838,25 +827,14 @@
 rb_mod_ancestors(VALUE mod)
 {
     VALUE p, ary = rb_ary_new();
-    VALUE origin = RCLASS_ORIGIN(mod);
 
-    p = mod;
-    if (origin == mod) {
-	origin = 0;
-    }
-    else {
-	p = RCLASS_SUPER(p);
-    }
-    for (; p; p = RCLASS_SUPER(p)) {
+    for (p = mod; p; p = RCLASS_SUPER(p)) {
 	if (FL_TEST(p, FL_SINGLETON))
 	    continue;
-	if (p == origin) {
-	    rb_ary_push(ary, mod);
-	}
-	else if (BUILTIN_TYPE(p) == T_ICLASS) {
+	if (BUILTIN_TYPE(p) == T_ICLASS) {
 	    rb_ary_push(ary, RBASIC(p)->klass);
 	}
-	else {
+	else if (p == RCLASS_ORIGIN(p)) {
 	    rb_ary_push(ary, p);
 	}
     }
Index: test/ruby/test_module.rb
===================================================================
--- test/ruby/test_module.rb	(revision 36265)
+++ test/ruby/test_module.rb	(revision 36266)
@@ -1243,31 +1243,37 @@
     def m1; [:M0] end
   end
   module M1
-    def m1; [:M1, super, :M1] end
+    def m1; [:M1, *super] end
   end
   module M2
-    def m1; [:M2, super, :M2] end
+    def m1; [:M2, *super] end
   end
   M3 = Module.new do
-    def m1; [:M3, super, :M3] end
+    def m1; [:M3, *super] end
   end
   module M4
-    def m1; [:M4, super, :M4] end
+    def m1; [:M4, *super] end
   end
-  class C0
+  class C
+    def m1; end
+  end
+  class C0 < C
     include M0
     prepend M1
-    def m1; [:C0, super, :C0] end
+    def m1; [:C0, *super] end
   end
   class C1 < C0
     prepend M2, M3
     include M4
-    def m1; [:C1, super, :C1] end
+    def m1; [:C1, *super] end
   end
 
   def test_prepend
+    obj = C0.new
+    expected = [:M1,:C0,:M0]
+    assert_equal(expected, obj.m1)
     obj = C1.new
-    expected = [:M2,[:M3,[:C1,[:M4,[:M1,[:C0,[:M0],:C0],:M1],:M4],:C1],:M3],:M2]
+    expected = [:M2,:M3,:C1,:M4,:M1,:C0,:M0]
     assert_equal(expected, obj.m1)
   end
 
@@ -1305,13 +1311,30 @@
     m = labeled_module("m")
     c = labeled_class("c") {prepend m}
     assert_equal([m, c], c.ancestors[0, 2], bug6658)
+
+    bug6662 = '[ruby-dev:45868]'
+    c2 = labeled_class("c2", c)
+    anc = c2.ancestors
+    assert_equal([c2, m, c, Object], anc[0..anc.index(Object)], bug6662)
   end
 
   def test_prepend_module_ancestors
     bug6659 = '[ruby-dev:45861]'
-    m0 = labeled_module("m0")
-    m1 = labeled_module("m1") {prepend m0}
+    m0 = labeled_module("m0") {def x; [:m0, *super] end}
+    m1 = labeled_module("m1") {def x; [:m1, *super] end; prepend m0}
+    m2 = labeled_module("m2") {def x; [:m2, *super] end; prepend m1}
+    c0 = labeled_class("c0") {def x; [:c0] end}
+    c1 = labeled_class("c1") {def x; [:c1] end; prepend m2}
+    c2 = labeled_class("c2", c0) {def x; [:c2, *super] end; include m2}
+
     assert_equal([m0, m1], m1.ancestors, bug6659)
+
+    bug6662 = '[ruby-dev:45868]'
+    assert_equal([m0, m1, m2], m2.ancestors, bug6662)
+    assert_equal([m0, m1, m2, c1], c1.ancestors[0, 4], bug6662)
+    assert_equal([:m0, :m1, :m2, :c1], c1.new.x)
+    assert_equal([c2, m0, m1, m2, c0], c2.ancestors[0, 5], bug6662)
+    assert_equal([:c2, :m0, :m1, :m2, :c0], c2.new.x)
   end
 
   def labeled_module(name, &block)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]