[svn:parrot] r35820 - trunk/src
[email protected] Tue, 20 Jan 2009 09:47:59 -0800 (PST)
| Newsgroups | perl.cvs.parrot |
|---|---|
| Message-ID | <[email protected]> |
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. */