Author: jonathan
Date: Tue Jan 20 09:47:58 2009
New Revision: 35820

Modified:
   trunk/src/oo.c

Log:
[core] Resolve RT#45999 by making role composition handle multis.

Modified: trunk/src/oo.c
==============================================================================
--- trunk/src/oo.c      (original)
+++ trunk/src/oo.c      Tue Jan 20 09:47:58 2009
@@ -1229,15 +1229,18 @@
 
         /* If we weren't excluded... */
         if (!excluded) {
-            /* Is there a method with this name already in the class?
-             * RT #45999 multi-method handling. */
+            /* Is there a method with this name already in the class? */
 
-            if (VTABLE_exists_keyed_str(interp, methods_hash, method_name))
-                /* Conflicts with something already in the class. */
-                Parrot_ex_throw_from_c_args(interp, NULL,
-                    EXCEPTION_ROLE_COMPOSITION_METHOD_CONFLICT,
-                    "A conflict occurred during role composition "
-                    "due to method '%S'.", method_name);
+            if (VTABLE_exists_keyed_str(interp, methods_hash, method_name)) {
+                /* Conflicts with something already in the class, unless it's a
+                 * multi-method. */
+                PMC *cur_entry = VTABLE_get_pmc_keyed_str(interp, 
methods_hash, method_name);
+                if (PMC_IS_NULL(cur_entry) || !VTABLE_isa(interp, cur_entry, 
CONST_STRING(interp, "MultiSub")))
+                    Parrot_ex_throw_from_c_args(interp, NULL,
+                        EXCEPTION_ROLE_COMPOSITION_METHOD_CONFLICT,
+                        "A conflict occurred during role composition "
+                        "due to method '%S'.", method_name);
+            }
 
             /* What about a conflict with ourslef? */
             if (VTABLE_exists_keyed_str(interp, proposed_add_methods,
@@ -1261,15 +1264,18 @@
             STRING * const alias_name = VTABLE_get_string_keyed_str(interp,
                 alias, method_name);
 
-            /* Is there a method with this name already in the class?
-             * RT #45999: multi-method handling. */
-            if (VTABLE_exists_keyed_str(interp, methods_hash, alias_name))
-                /* Conflicts with something already in the class. */
-                Parrot_ex_throw_from_c_args(interp, NULL,
-                    EXCEPTION_ROLE_COMPOSITION_METHOD_CONFLICT,
-                    "A conflict occurred during role composition"
-                    " due to the aliasing of '%S' to '%S'.",
-                    method_name, alias_name);
+            /* Is there a method with this name already in the class? If it's
+             * not a multi-method, error. */
+            if (VTABLE_exists_keyed_str(interp, methods_hash, alias_name)) {
+                PMC *cur_entry = VTABLE_get_pmc_keyed_str(interp, 
methods_hash, alias_name);
+                if (PMC_IS_NULL(cur_entry) || !VTABLE_isa(interp, cur_entry, 
CONST_STRING(interp, "MultiSub")))
+                    /* Conflicts with something already in the class. */
+                    Parrot_ex_throw_from_c_args(interp, NULL,
+                        EXCEPTION_ROLE_COMPOSITION_METHOD_CONFLICT,
+                        "A conflict occurred during role composition"
+                        " due to the aliasing of '%S' to '%S'.",
+                        method_name, alias_name);
+            }
 
             /* What about a conflict with ourslef? */
             if (VTABLE_exists_keyed_str(interp, proposed_add_methods,
@@ -1298,7 +1304,30 @@
                                         proposed_add_methods, method_name);
 
         /* Add it to the methods of the class. */
-        VTABLE_set_pmc_keyed_str(interp, methods_hash, method_name, 
cur_method);
+        PMC *cur_entry = VTABLE_get_pmc_keyed_str(interp, methods_hash, 
method_name);
+        if (VTABLE_isa(interp, cur_method, CONST_STRING(interp, "MultiSub"))) {
+            /* The thing we're adding is a multi-sub, but is the thing in the
+             * class already a multi-sub? */
+            if (!PMC_IS_NULL(cur_entry) && VTABLE_isa(interp, cur_entry, 
CONST_STRING(interp, "MultiSub"))) {
+                /* Class already has a multi-sub; need to merge our methods 
into it. */
+                INTVAL num_subs = VTABLE_elements(interp, cur_method);
+                INTVAL i;
+                for (i = 0; i < num_subs; i++)
+                    VTABLE_push_pmc(interp, cur_entry, 
VTABLE_get_pmc_keyed_int(interp,
+                            cur_method, i));
+            }
+            else {
+                /* It's not, and we didn't conflict so much be no entry. Just 
stick it in. */
+                VTABLE_set_pmc_keyed_str(interp, methods_hash, method_name, 
cur_method);
+            }
+        }
+        else {
+            /* Are we adding into a multi-sub? */
+            if (!PMC_IS_NULL(cur_entry) && VTABLE_isa(interp, cur_entry, 
CONST_STRING(interp, "MultiSub")))
+                VTABLE_push_pmc(interp, cur_entry, cur_method);
+            else
+                VTABLE_set_pmc_keyed_str(interp, methods_hash, method_name, 
cur_method);
+        }
     }
 
     /* Add this role to the roles list. */

Reply via email to