Let state sub fwd decls and nested subs work in anons
authorFather Chrysostomos <sprout@cpan.org>
Thu, 26 Jul 2012 19:38:14 +0000 (12:38 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Sun, 16 Sep 2012 05:45:03 +0000 (22:45 -0700)
commit10342479afca0484c66269733fcc2f4a1fbabbb7
treee3e43797240ed502e5f22246bb4d32ca997c7dbe
parent2a388207e072a645aa29f0b2b18f07d9a55cbf5e
Let state sub fwd decls and nested subs work in anons

I had this working:

state sub foo;
sub other {
    sub foo { # defines the state sub declared outside
        ...
    }
}

But it failed inside an anonymous subroutine:

sub {
    state sub foo;
    sub other {
        sub foo { # defines the state sub declared outside
            ...
        }
    }
}

When an anonymous (or otherwise clonable) sub is cloned, any state
vars, and, likewise, any state subs, inside it are cloned, too.

In the first example above the state sub forward declaration creates
a subroutine stub.  The ‘other’ sub’s ‘sub foo’ declaration creates a
pad entry in other’s pad that closes over the outer foo immediately,
so the same stub is visible in two pads.  The sub foo {} declaration
uses that stub.

When the outer sub containing the forward declaration is clonable,
the pad entry is not closed over immediately at compile time, because
the pad entry is just a prototype, not the actual value that will be
shared by the clone and its nested subs.  So the inner pad entry does
not contain the sub.

So the actual creation of the sub, if it only looks at the inner
pad (other’s pad), will not see the stub, and will not attach a
body to it.

This was the result:

$ ./miniperl -e 'CORE::state sub foo; CORE::state sub bar { sub foo {warn called} }; foo()'
called at -e line 1.
$ ./miniperl -e 'sub { CORE::state sub foo; CORE::state sub bar { sub foo {warn called} }; foo() }->()'
Undefined subroutine &foo called at -e line 1.

This commit fixes that by having newMYSUB follow the CvOUTSIDE chain
to find the original pad entry where it defines the sub, if the for-
ward declaration is occurs outside and has not been closed over yet.
op.c
t/cmd/lexsub.t