summaryrefslogtreecommitdiff
path: root/t/cmd
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2012-08-03 09:23:15 -0700
committerFather Chrysostomos <sprout@cpan.org>2012-09-15 22:45:05 -0700
commit6d5c21479838db78689e08afd075ef4e9100ef0d (patch)
tree44db00c7bbbae895f1e3208ffcd3a43b719373cb /t/cmd
parentfead5351141134064bc3069932e04930bd96eb0e (diff)
downloadperl-6d5c21479838db78689e08afd075ef4e9100ef0d.tar.gz
Clone my subs on scope entry
The pad slot for a my sub now holds a stub with a prototype CV attached to it by proto magic. The prototype is cloned on scope entry. The stub in the pad is used when cloning, so any code that references the sub before scope entry will be able to see that stub become defined, making these behave similarly: our $x; BEGIN { $x = \&foo } sub foo { } our $x; my sub foo { } BEGIN { $x = \&foo } Constants are currently not cloned, but that may cause bugs in pad_push. I’ll have to look into that. On scope exit, lexical CVs go through leave_scope’s SAVEt_CLEARSV sec- tion, like lexical variables. If the sub is referenced elsewhere, it is abandoned, and its proto magic is stolen and attached to a new stub stored in the pad. If the sub is not referenced elsewhere, it is undefined via cv_undef. To clone my subs on scope entry, we create a sequence of introcv and clonecv ops. See the huge comment in block_end that explains why we need two separate ops for each CV. To allow my subs to be defined in inner subs (my sub foo; sub { sub foo {} }), pad_add_name_pvn and S_pad_findlex now upgrade the entry for a my sub to a CV to begin with, so that fake entries added to pads (fake entries are those that reference outer pads) can share the same CV. Otherwise newMYSUB would have to add the CV to every pad that closes over the ‘my sub’ declaration. newMYSUB no longer throws away the initial value replacing it with a new one. Prototypes are not currently visible to sub calls at compile time, because the lexer sees the empty stub. A future commit will solve that. When I added name heks to CV’s I made mistakes in a few places, by not turning on the CVf_NAMED flag, or by not clearing the field when free- ing the hek. Those code paths were not exercised enough by state subs, so the problems did not show up till now. So this commit fixes those, too. One of the tests in lexsub.t, involving foreach loops, was incorrect, and has been fixed. Another test has been added to the end for a par- ticular case of state subs closing over my subs that I broke when ini- tially trying to get sibling my subs to close over each other, before I had separate introcv and clonecv ops.
Diffstat (limited to 't/cmd')
-rw-r--r--t/cmd/lexsub.t37
1 files changed, 20 insertions, 17 deletions
diff --git a/t/cmd/lexsub.t b/t/cmd/lexsub.t
index fa4ccdc5d2..348facf933 100644
--- a/t/cmd/lexsub.t
+++ b/t/cmd/lexsub.t
@@ -8,7 +8,7 @@ BEGIN {
*bar::like = *like;
}
no warnings 'deprecated';
-plan 106;
+plan 107;
# -------------------- our -------------------- #
@@ -84,9 +84,6 @@ sub bar::c { 43 }
# -------------------- state -------------------- #
-sub on { $::TODO = ' ' }
-sub off { $::TODO = undef }
-
use 5.01; # state
{
state sub foo { 44 }
@@ -415,33 +412,31 @@ sub mmake_closure {
}
$sub1 = mmake_closure 48;
$sub2 = mmake_closure 49;
-on;
-is eval { &$sub1 }, 48, 'my sub in closure (1)';
-is eval { &$sub2 }, 49, 'my sub in closure (2)';
+is &$sub1, 48, 'my sub in closure (1)';
+is &$sub2, 49, 'my sub in closure (2)';
# Test that they are cloned in named subs.
{
use warnings;
my $w;
local $SIG{__WARN__} = sub { $w .= shift };
eval '#line 65 teetet
- sub foom {
+ sub mfoom {
my $x = shift;
my sub poom { $x }
- eval{\&poom}
+ \&poom
}
';
is $w, undef, 'my subs get no "Variable will not stay shared" messages';
- my $poom = foom(27);
- my $poom2 = foom(678);
- is eval { $poom->() }, 27, 'my subs closing over outer my var (1)';
- is eval { $poom2->() }, 678, 'my subs closing over outer my var (2)';
+ my $poom = mfoom(27);
+ my $poom2 = mfoom(678);
+ is $poom->(), 27, 'my subs closing over outer my var (1)';
+ is $poom2->(), 678, 'my subs closing over outer my var (2)';
my $x = 43;
my sub aoeu;
for $x (765) {
my sub etetetet { $x }
- my sub aoeu { $x }
+ sub aoeu { $x }
is etetetet, 765, 'my sub respects for() localisation';
-off;
is aoeu, 43, 'unless it is declared outside the for loop';
}
}
@@ -463,11 +458,9 @@ sub make_anon_with_my_sub{
&$s;
# And make sure the my subs were actually cloned.
-on;
isnt make_anon_with_my_sub->(0), &$s(0),
'my subs in anon subs are cloned';
isnt &$s(0), &$s(0), 'at each invocation of the enclosing sub';
-off;
}
{
my sub BEGIN { exit };
@@ -485,3 +478,13 @@ off;
is $w, "Subroutine redef redefined at pygpyf line 56.\n",
"sub redefinition warnings from my subs";
}
+
+# -------------------- Interactions (and misc tests) -------------------- #
+
+is sub {
+ my sub s1;
+ my sub s2 { 3 };
+ sub s1 { state sub foo { \&s2 } foo }
+ s1
+ }->()(), 3, 'state sub inside my sub closing over my sub uncle';
+