The problem is that doing an explicit tailcall of a continuation without set_params passes the sub's args to the continuation, instead of no args. As a result, I was getting weird param count mismatch errors in cases where I was neither passing nor receiving anything. (This is why I hadn't noticed this until Leo turned on param checking by default; I assume this is longstanding behavior.)
This brings up a couple of issues: 1. For purposes of error checking, Parrot obviously considers that tailcall passes arguments, as for function calls, even when tail-calling a continuation in order to effect a return. Should continuations be handled specially, or do we want to define that "tailcall" always means "call"? 2. Passing the sub args to a tail-called sub/continuation strikes me as buggy, but I can't think of a way to fix this without breaking the "feature" that it is currently possible to call get_params multiple times. One such fix is attached. It works by having parrot_pass_args "use up" the args and params in the PARROT_OP_get_params_pc case. Doing this for the other cases doesn't seem to break anything else, and strikes me as a good idea; should I make it happen for all parrot_pass_args calls? Alternatively, passing the sub args could be defined as expected behavior, but that seems error-prone. If I hear no objections to flushing "multiple get_params" (nor exhortations to generalize "using up" the args), I will commit the patch as-is. -- Bob Rogers http://rgrjr.dyndns.org/
Index: src/inter_call.c =================================================================== --- src/inter_call.c (revision 11638) +++ src/inter_call.c (working copy) @@ -1082,6 +1082,8 @@ if (what == PARROT_OP_get_params_pc) { dst_pc = interpreter->current_params; src_pc = interpreter->current_args; + /* the args and params are now 'used.' */ + interpreter->current_args = NULL; interpreter->current_params = NULL; action = "params"; } Index: t/op/calling.t =================================================================== --- t/op/calling.t (revision 11638) +++ t/op/calling.t (working copy) @@ -701,6 +701,9 @@ bar_ret OUTPUT +SKIP: { + skip("can't get_params twice any more.", 1); + pasm_output_is(<<'CODE', <<'OUTPUT', "get_params twice"); .pcc_sub main: new P16, .String @@ -740,6 +743,8 @@ back OUTPUT +} # end of SKIP. + pir_output_is(<<'CODE', <<'OUTPUT', "empty args"); .sub main :main $P0 = new String @@ -855,20 +860,25 @@ pir_output_is(<<'CODE', <<'OUTPUT', "type conversion - native"); .sub main :main - foo(42, "42", 42.20) + foo_int(42, "42", 42.20) + foo_float(42, "42", 42.20) + foo_string(42, "42", 42.20) .end -.sub foo +.sub foo_int get_params "(0,0,0)", $I0, $I1, $I2 print_item $I0 print_item $I1 print_item $I2 print_newline - # yeah fetch args again +.end +.sub foo_float get_params "(0,0,0)", $N0, $N1, $N2 print_item $N0 print_item $N1 print_item $N2 print_newline +.end +.sub foo_string get_params "(0,0,0)", $S0, $S1, $S2 print_item $S0 print_item $S1 @@ -1604,6 +1614,32 @@ ok 2 OUTPUT +# this is a regression test for a bug in which tail-calling without set_args +# used the args of the sub. +pir_output_is(<<'CODE', <<'OUTPUT', "tail explicit continuation, no args"); +.sub main :main + .local string result + result = "not ok 2\n" + .local pmc cont + cont = new .Continuation + set_addr cont, cont_dest + bar(cont, "ok 1\n") + print "oops\n" +cont_dest: + print "ok 2\n" +.end + +.sub bar + .param pmc cc + .param string s + print s + tailcall cc +.end +CODE +ok 1 +ok 2 +OUTPUT + pir_output_is(<<'CODE', <<'OUTPUT', "call evaled vtable code"); .sub main :main .local string s @@ -2179,5 +2215,5 @@ /duplicate name/ OUTPUT ## remember to change the number of tests :-) -BEGIN { plan tests => 86 } +BEGIN { plan tests => 87 }