summaryrefslogtreecommitdiff
path: root/t/cmd
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2012-07-09 06:29:09 -0700
committerFather Chrysostomos <sprout@cpan.org>2012-09-15 22:45:01 -0700
commite07561e6ac7f381061f112bee32ebc779683a84c (patch)
tree86ad55151c90232dceb0b431f846beafe5434a56 /t/cmd
parent20d337866901b1d0118edc4ff2cb2407b27e0275 (diff)
downloadperl-e07561e6ac7f381061f112bee32ebc779683a84c.tar.gz
Clone state subs in anon subs
Since state variables are not shared between closures, but only between invocations of the same closure, state subs should behave the same way. This was a little tricky. When we clone a sub, we now clone inner state subs at the same time. When walking through the pad, cloning items, we cannot simply clone the inner sub when we see it, because it may close over things we haven’t cloned yet: sub { state sub foo; my $x sub foo { $x } } We can’t just delay cloning it and do it afterwards, because they may be multiple subs closing over each other: sub { state sub foo; state sub bar; sub foo { \&bar } sub bar { \&foo } } So *all* the entries in the new pad must be filled before any inner subs can be cloned. So what we do is put a stub in place of the cloned sub. And then in a second pass clone the inner subs, reusing the stubs from the first pass.
Diffstat (limited to 't/cmd')
-rw-r--r--t/cmd/lexsub.t30
1 files changed, 25 insertions, 5 deletions
diff --git a/t/cmd/lexsub.t b/t/cmd/lexsub.t
index d940d1c116..e285a84366 100644
--- a/t/cmd/lexsub.t
+++ b/t/cmd/lexsub.t
@@ -8,7 +8,7 @@ BEGIN {
*bar::like = *like;
}
no warnings 'deprecated';
-plan 58;
+plan 62;
# -------------------- our -------------------- #
@@ -199,18 +199,16 @@ package main;
# Since state vars inside anonymous subs are cloned at the same time as the
# anonymous subs containing them, the same should happen for state subs.
sub make_closure {
- state $x = shift;
+ my $x = shift;
sub {
state sub foo { $x }
- eval {foo}
+ foo
}
}
$sub1 = make_closure 48;
$sub2 = make_closure 49;
is &$sub1, 48, 'state sub in closure (1)';
-on;
is &$sub2, 49, 'state sub in closure (2)';
-off;
# But we need to test that state subs actually do persist from one invoca-
# tion of a named sub to another (i.e., that they are not my subs).
{
@@ -238,6 +236,28 @@ on;
off;
}
}
+# And we also need to test that multiple state subs can close over each
+# other’s entries in the parent subs pad, and that cv_clone is not con-
+# fused by that.
+sub make_anon_with_state_sub{
+ sub {
+ state sub s1;
+ state sub s2 { \&s1 }
+ sub s1 { \&s2 }
+ if (@_) { return \&s1 }
+ is s1,\&s2, 'state sub in anon closure closing over sibling state sub';
+ is s2,\&s1, 'state sub in anon closure closing over sibling state sub';
+ }
+}
+{
+ my $s = make_anon_with_state_sub;
+ &$s;
+
+ # And make sure the state subs were actually cloned.
+ isnt make_anon_with_state_sub->(0), &$s(0),
+ 'state subs in anon subs are cloned';
+ is &$s(0), &$s(0), 'but only when the anon sub is cloned';
+}
{
state sub BEGIN { exit };
pass 'state subs are never special blocks';