Fix return value of state assignment ($x=state $y=$z).
Rafael Garcia-Suarez [Tue, 27 Mar 2007 09:42:44 +0000 (09:42 +0000)]
Fix a form of state assignment (state($x)=$y).
Minor optimisation in pp_aassign for state variables.
New tests.

p4raw-id: //depot/perl@30772

op.c
pp_hot.c
t/op/state.t

diff --git a/op.c b/op.c
index 23b4b81..f05be0b 100644 (file)
--- a/op.c
+++ b/op.c
@@ -3925,6 +3925,17 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
                lop = lop->op_sibling;
            }
        }
+       else if (((left->op_private & (OPpLVAL_INTRO | OPpPAD_STATE))
+                   == (OPpLVAL_INTRO | OPpPAD_STATE))
+               && (   left->op_type == OP_PADSV
+                   || left->op_type == OP_PADAV
+                   || left->op_type == OP_PADHV
+                   || left->op_type == OP_PADANY))
+       {
+           o->op_private |= OPpASSIGN_STATE;
+           /* hijacking PADSTALE for uninitialized state variables */
+           SvPADSTALE_on(PAD_SVl(left->op_targ));
+       }
 
        if (right && right->op_type == OP_SPLIT) {
            OP* tmpop = ((LISTOP*)right)->op_first;
index f01a3e0..83ed613 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -130,8 +130,11 @@ PP(pp_sassign)
     else if (PL_op->op_private & OPpASSIGN_STATE) {
        if (SvPADSTALE(right))
            SvPADSTALE_off(right);
-       else
+       else {
+           (void)POPs;
+           PUSHs(right);
            RETURN; /* ignore assignment */
+       }
     }
     if (PL_tainting && PL_tainted && !SvTAINTED(left))
        TAINT_NOT;
@@ -969,6 +972,12 @@ PP(pp_aassign)
     int duplicates = 0;
     SV **firsthashrelem = NULL;        /* "= 0" keeps gcc 2.95 quiet  */
 
+    if (PL_op->op_private & OPpASSIGN_STATE) {
+       if (SvPADSTALE(*firstlelem))
+           SvPADSTALE_off(*firstlelem);
+       else
+           RETURN; /* ignore assignment */
+    }
 
     PL_delaymagic = DM_DELAY;          /* catch simultaneous items */
     gimme = GIMME_V;
@@ -986,12 +995,6 @@ PP(pp_aassign)
            }
        }
     }
-    if (PL_op->op_private & OPpASSIGN_STATE) {
-       if (SvPADSTALE(*firstlelem))
-           SvPADSTALE_off(*firstlelem);
-       else
-           RETURN; /* ignore assignment */
-    }
 
     relem = firstrelem;
     lelem = firstlelem;
index 9f618b0..57b46ab 100644 (file)
@@ -10,7 +10,7 @@ BEGIN {
 use strict;
 use feature "state";
 
-plan tests => 37;
+plan tests => 46;
 
 ok( ! defined state $uninit, q(state vars are undef by default) );
 
@@ -20,23 +20,27 @@ sub stateful {
     state $x;
     state $y = 1;
     my $z = 2;
-    return ($x++, $y++, $z++);
+    state ($t) = 3;
+    return ($x++, $y++, $z++, $t++);
 }
 
-my ($x, $y, $z) = stateful();
+my ($x, $y, $z, $t) = stateful();
 is( $x, 0, 'uninitialized state var' );
 is( $y, 1, 'initialized state var' );
 is( $z, 2, 'lexical' );
+is( $t, 3, 'initialized state var, list syntax' );
 
-($x, $y, $z) = stateful();
+($x, $y, $z, $t) = stateful();
 is( $x, 1, 'incremented state var' );
 is( $y, 2, 'incremented state var' );
 is( $z, 2, 'reinitialized lexical' );
+is( $t, 4, 'incremented state var, list syntax' );
 
-($x, $y, $z) = stateful();
+($x, $y, $z, $t) = stateful();
 is( $x, 2, 'incremented state var' );
 is( $y, 3, 'incremented state var' );
 is( $z, 2, 'reinitialized lexical' );
+is( $t, 5, 'incremented state var, list syntax' );
 
 # in a nested block
 
@@ -126,6 +130,18 @@ is( $xsize, 0, 'uninitialized state array' );
 $xsize = stateful_array();
 is( $xsize, 1, 'uninitialized state array after one iteration' );
 
+sub stateful_array_init {
+    state @x = (1, 2);
+    push @x, 'x';
+    return $#x;
+}
+
+$xsize = stateful_array_init();
+is( $xsize, 2, 'initialized state array' );
+
+$xsize = stateful_array_init();
+is( $xsize, 3, 'initialized state array after one iteration' );
+
 # hash state vars
 
 sub stateful_hash {
@@ -139,6 +155,17 @@ is( $xhval, 0, 'uninitialized state hash' );
 $xhval = stateful_hash();
 is( $xhval, 1, 'uninitialized state hash after one iteration' );
 
+sub stateful_hash_init {
+    state %hx = (foo => 10);
+    return $hx{foo}++;
+}
+
+$xhval = stateful_hash_init();
+is( $xhval, 10, 'initialized state hash' );
+
+$xhval = stateful_hash_init();
+is( $xhval, 11, 'initialized state hash after one iteration' );
+
 # state declaration with a list
 
 sub statelist {
@@ -175,3 +202,10 @@ sub noseworth {
     noseworth($level - 1) if $level;
 }
 noseworth(2);
+
+# Assignment return value
+
+sub pugnax { my $x = state $y = 42; $y++; $x; }
+
+is( pugnax(), 42, 'scalar state assignment return value' );
+is( pugnax(), 43, 'scalar state assignment return value' );