If you enable PARROT_ERRORS_PARAM_COUNT_FLAG, parrot_pass_args
miscounts a :flat array as a single argument, leading to inappropriate
errors.  This patch fixes arg counting, adds tests to cover, and
improves the error messages.  If parrot_pass_args_fromc supports :flat,
then it may have similar problems . . .

                                        -- Bob Rogers
                                           http://rgrjr.dyndns.org/

Index: src/inter_call.c
===================================================================
--- src/inter_call.c    (revision 10513)
+++ src/inter_call.c    (working copy)
@@ -238,6 +238,8 @@
         st->src.slurp = p_arg;
         st->src.slurp_i = 0;
         st->src.slurp_n = VTABLE_elements(interpreter, p_arg);
+       /* the -1 is because the :flat PMC itself doesn't count. */
+        st->n_actual_args += st->src.slurp_n-1;
         return Parrot_fetch_arg(interpreter, st);
     }
 
@@ -672,6 +674,7 @@
     todo = Parrot_init_arg_op(interpreter, dest_ctx, dst_pc, &st.dest);
     Parrot_init_arg_op(interpreter, src_ctx, src_pc, &st.src);
     st.opt_so_far = 0;  /* XXX */
+    st.n_actual_args = st.src.n;  /* initial guess, adjusted for :flat args */
     while (todo) {
         Parrot_fetch_arg(interpreter, &st);
         Parrot_convert_arg(interpreter, &st);
@@ -702,24 +705,43 @@
          * we are returning 1 retval to caller on behalf
          * of the NCI (a PIR method had already returned
          * all and doesn't run anything after the
-         * tailcall - ignore/fix missing arg_count
+         * tailcall - ignore arg_count
          */
-        st.src.i = st.src.n;
     }
+    else {
+        /*
+         * compute the range of expected arguments.  we do this here when we
+         * know we need to check it.  on the other hand, we must compute
+         * st.n_actual_args as we go, as it's harder to get :flat array lengths
+         * after the fact.
+         */
+        int slurpy_p = (st.dest.sig
+                        & (PARROT_ARG_SLURPY_ARRAY|PARROT_ARG_OPT_FLAG));
+        int max_expected_args = (slurpy_p ? st.dest.n-1 : st.dest.n);
+        int min_expected_args = max_expected_args;
+        int i;
+        /* allow for optionals. */
+        for (i = 0; i < st.dest.n; i++) {
+            if (st.dest.sig & PARROT_ARG_OPTIONAL)
+                min_expected_args--;
+        }
 
-    if (st.src.i > st.src.n) {
-        if (!(st.dest.sig & (PARROT_ARG_OPTIONAL|
-                        PARROT_ARG_SLURPY_ARRAY|PARROT_ARG_OPT_FLAG))) {
+        /* arg checks. */
+        if (st.n_actual_args < min_expected_args) {
             real_exception(interpreter, NULL, E_ValueError,
-                    "too few arguments passed (%d) - %d %s expected",
-                    st.src.n, st.dest.n, action);
+                    "too few arguments passed (%d) - %s%d %s expected",
+                    st.n_actual_args,
+                    (min_expected_args < max_expected_args ? "at least " : ""),
+                    min_expected_args, action);
         }
+        else if (! slurpy_p && st.n_actual_args > max_expected_args) {
+            real_exception(interpreter, NULL, E_ValueError,
+                    "too many arguments passed (%d) - %s%d %s expected",
+                    st.n_actual_args,
+                    (min_expected_args < max_expected_args ? "at most " : ""),
+                    max_expected_args, action);
+        }
     }
-    else if (st.src.n && st.src.i < st.src.n) {
-        real_exception(interpreter, NULL, E_ValueError,
-                "too many arguments passed (%d) - %d %s expected",
-                st.src.n, st.dest.n, action);
-    }
 
     /* skip the get_params opcode - all done here */
     return dst_pc + st.dest.n + 2;
Index: include/parrot/inter_call.h
===================================================================
--- include/parrot/inter_call.h (revision 10513)
+++ include/parrot/inter_call.h (working copy)
@@ -50,6 +50,7 @@
     struct call_state_1 dest;
     UnionVal val;
     int opt_so_far;
+    int n_actual_args;
 };
 
 int Parrot_init_arg_sig(Interp *, parrot_context_t *ctx,
Index: t/op/calling.t
===================================================================
--- t/op/calling.t      (revision 10513)
+++ t/op/calling.t      (working copy)
@@ -1155,6 +1155,105 @@
 1 2 3 4
 OUTPUT
 
+pir_output_is(<<'CODE', <<'OUTPUT', "right number of args via :flat");
+.sub _fn1
+    .param int arg1
+    .param int arg2
+    .param int arg3
+    .param int arg4
+    print arg1
+    print ' '
+    print arg2
+    print ' '
+    print arg3
+    print ' '
+    print arg4
+    print "\n"
+.end
+.sub main :main
+    .include "errors.pasm"
+    errorson .PARROT_ERRORS_PARAM_COUNT_FLAG
+    $P30 = new Integer
+    $P30 = 2
+    $P31 = new Integer
+    $P31 = 3
+    $P34 = new Array
+    $P34 = 3
+    $P34[0] = $P30
+    $P34[1] = $P31
+    $P34[2] = $P30
+    $P35 = _fn1(1, $P34 :flat)
+.end
+CODE
+1 2 3 2
+OUTPUT
+
+pir_output_like(<<'CODE', <<'OUTPUT', "too many args via :flat");
+.sub _fn1
+    .param int arg1
+    .param int arg2
+    .param int arg3
+    .param int arg4
+    print arg1
+    print ' '
+    print arg2
+    print ' '
+    print arg3
+    print ' '
+    print arg4
+    print "\n"
+.end
+.sub main :main
+    .include "errors.pasm"
+    errorson .PARROT_ERRORS_PARAM_COUNT_FLAG
+    $P30 = new Integer
+    $P30 = 2
+    $P31 = new Integer
+    $P31 = 3
+    $P34 = new Array
+    $P34 = 4
+    $P34[0] = $P30
+    $P34[1] = $P31
+    $P34[2] = $P30
+    $P34[3] = $P31
+    $P35 = _fn1(1, $P34 :flat)
+.end
+CODE
+/too many arguments passed \(5\) - 4 params expected/
+OUTPUT
+
+pir_output_like(<<'CODE', <<'OUTPUT', "too few args via :flat");
+.sub _fn1
+    .param int arg1
+    .param int arg2
+    .param int arg3
+    .param int arg4
+    print arg1
+    print ' '
+    print arg2
+    print ' '
+    print arg3
+    print ' '
+    print arg4
+    print "\n"
+.end
+.sub main :main
+    .include "errors.pasm"
+    errorson .PARROT_ERRORS_PARAM_COUNT_FLAG
+    $P30 = new Integer
+    $P30 = 2
+    $P31 = new Integer
+    $P31 = 3
+    $P34 = new Array
+    $P34 = 2
+    $P34[0] = $P30
+    $P34[1] = $P31
+    $P35 = _fn1(1, $P34 :flat)
+.end
+CODE
+/too few arguments passed \(3\) - 4 params expected/
+OUTPUT
+
 pir_output_is(<<'CODE', <<'OUTPUT', "tailcall to NCI");
 .sub main :main
     .local pmc s
@@ -1474,5 +1573,5 @@
 
 
 ## remember to change the number of tests :-)
-BEGIN { plan tests => 54; }
+BEGIN { plan tests => 57; }
 

Reply via email to