Author: jonathan
Date: Sat Aug 16 09:51:54 2008
New Revision: 30270

Added:
   trunk/languages/perl6/t/pmc/perl6multisub-dispatch-tiebreak.t   (contents, 
props changed)
Modified:
   trunk/languages/perl6/src/pmc/perl6multisub.pmc

Log:
[rakudo] Tie-break on constraints, plus a test for this.

Modified: trunk/languages/perl6/src/pmc/perl6multisub.pmc
==============================================================================
--- trunk/languages/perl6/src/pmc/perl6multisub.pmc     (original)
+++ trunk/languages/perl6/src/pmc/perl6multisub.pmc     Sat Aug 16 09:51:54 2008
@@ -382,7 +382,7 @@
 
 static PMC* do_dispatch(PARROT_INTERP, candidate_info** candidates, PMC *args, 
int many,
                         int num_candidates, opcode_t *next) {
-    INTVAL i, type_check_count;
+    INTVAL i, j, type_check_count;
     INTVAL num_args = VTABLE_elements(interp, args);
     candidate_info **cur_candidate = candidates;
     candidate_info **possibles = mem_allocate_n_typed(num_candidates, 
candidate_info*);
@@ -435,7 +435,60 @@
         cur_candidate++;
     }
 
-    /* XXX Loooooads of other disambiguation logic comes here. */
+    /* If we have multiple candidates left, tie-break on any constraints. */
+    if (possibles_count > 1) {
+        candidate_info **matching = mem_allocate_n_typed(possibles_count, 
candidate_info*);
+        candidate_info **constraint_free = 
mem_allocate_n_typed(possibles_count, candidate_info*);
+        INTVAL matching_count = 0;
+        INTVAL constraint_free_count = 0;
+        for (i = 0; i < possibles_count; i++) {
+            /* Check if we match any constraints. */
+            INTVAL constraint_checked = 0;
+            INTVAL constraint_failed = 0;
+            for (j = 0; j < possibles[i]->num_types; j++) {
+                PMC *type_obj = possibles[i]->constraints[j];
+                if (!PMC_IS_NULL(type_obj)) {
+                    PMC *param = VTABLE_get_pmc_keyed_int(interp, args, j);
+                    PMC *result = Parrot_runops_fromc_args(interp, type_obj,
+                            "PP", param);
+                    constraint_checked = 1;
+                    if (!VTABLE_get_integer(interp, result)) {
+                        constraint_failed = 1;
+                        break;
+                    }
+                }
+            }
+            if (!constraint_failed) {
+                if (constraint_checked) {
+                    matching[matching_count] = possibles[i];
+                    matching_count++;
+                }
+                else {
+                    constraint_free[constraint_free_count] = possibles[i];
+                    constraint_free_count++;
+                }
+            }
+        }
+
+        /* If we did find constraints to check, choose the matching over the
+         * ones without any constraints. */
+        if (matching_count) {
+            mem_sys_free(possibles);
+            mem_sys_free(constraint_free);
+            possibles = matching;
+            possibles_count = matching_count;
+        }
+        else if (constraint_free_count) {
+            mem_sys_free(possibles);
+            mem_sys_free(matching);
+            possibles = constraint_free;
+            possibles_count = constraint_free_count;
+        }
+    }
+
+    /* XXX Check is default trait */
+
+    /* XXX If still none/ambiguous, try and find a proto to call. */
 
     if (!many) {
         /* Need a unique candidate. */

Added: trunk/languages/perl6/t/pmc/perl6multisub-dispatch-tiebreak.t
==============================================================================
--- (empty file)
+++ trunk/languages/perl6/t/pmc/perl6multisub-dispatch-tiebreak.t       Sat Aug 
16 09:51:54 2008
@@ -0,0 +1,93 @@
+#! ../../parrot
+# Copyright (C) 2007-2008, The Perl Foundation.
+# $Id$
+
+=head1 NAME
+
+t/pmc/perl6multisub-dispatch-type.t - Type based dispatch tests
+
+=head1 SYNOPSIS
+
+    % prove t/pmc/perl6multisub-dispatch-type.t
+
+=head1 DESCRIPTION
+
+Tests for type based dispatch using the Perl 6 MultiSub PMC.
+
+=cut
+
+.loadlib 'perl6_group'
+
+.sub main :main
+    .include 'include/test_more.pir'
+    load_bytecode "perl6.pbc"
+
+    plan(2)
+
+    'constraint_tiebreak'()
+.end
+
+
+.sub 'constraint_tiebreak'
+    $P0 = new "Perl6MultiSub"
+    $P1 = find_global 'constraint_tiebreak_1'
+    $P2 = null
+    'attach_sig'($P1, $P2)
+    push $P0, $P1
+    $P1 = find_global 'constraint_tiebreak_2'
+    $P2 = find_global 'constraint_tiebreak_2_con'
+    'attach_sig'($P1, $P2)
+    push $P0, $P1
+
+    $P1 = new 'Int'
+    $P1 = 42
+    $I0 = $P0($P1)
+    is($I0, 2, 'constraint tie-breaks')
+    $P1 = 13
+    $I0 = $P0($P1)
+    is($I0, 1, 'constraint tie-breaks')
+.end
+.sub 'constraint_tiebreak_1'
+    .param pmc a
+    .return (1)
+.end
+.sub 'constraint_tiebreak_2'
+    .param pmc a
+    .return (2)
+.end
+.sub 'constraint_tiebreak_2_con'
+    .param int i
+    $I0 = i == 42
+    .return ($I0)
+.end
+
+.sub 'attach_sig'
+    .param pmc sub
+    .param pmc constraints :slurpy
+    
+    # Make signature.
+    .local pmc any
+    any = get_hll_global 'Any'
+    $P0 = new 'Signature'
+    $P1 = new 'Perl6Array'
+    setattribute $P0, "@!params", $P1
+    .local pmc it, con
+    it = iter constraints
+  param_loop:
+    unless it goto param_loop_end
+    con = shift it
+    $P2 = new 'Perl6Hash'
+    $P2["type"] = any
+    $P2["constraints"] = con
+    push $P1, $P2
+    goto param_loop
+  param_loop_end:
+
+    setprop sub, '$!signature', $P0
+.end
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:

Reply via email to