Another more detailed test suggests this has nothing to do with the multiple instances being present. Even a foreach loop over a single value is enough to upset it:
class Generated {
foreach my $letter (qw( x )) {
printf STDERR "\$letter is %#x\n", \$letter;
Devel::MAT::Dumper::dump( "prior-method.pmat" );
my $code = method {
return uc $letter;
};
printf STDERR "\$code is %#x\n", $code;
Devel::MAT::Dumper::dump( "subseq-method.pmat" );
no strict 'refs';
*$letter = $code;
}
}
Output:
$letter is 0x55dcb0bd7688
TODO: savestack type=10
$code is 0x55dcb047d1d0
TODO: savestack type=10
(ignore the TODO lines; they are Devel::MAT::Dumper complaining about an unrecognised SAVEt_FREEPV)
Analysing these in the `subseq-method.pmat` file shows us:
$ pmat subseq-method.pmat
Perl memory dumpfile from perl 5.30.0 threaded
Heap contains 23573 objects
Show quoted textpmat> show 0x55dcb0bd7688
SCALAR(PV) at 0x55dcb0bd7688 with refcount 2
size 50 bytes
PV="x"
PVLEN 1
Show quoted textpmat> identify 0x55dcb0bd7688
SCALAR(PV) at 0x55dcb0bd7688 is:
├─a constant of CODE() at 0x55dcb045a6c8=main_cv, which is:
│ └─the main code
└─the lexical $letter at depth 1 of CODE() at 0x55dcb045a6c8=main_cv, which is:
└─the main code
(as anticipated)
Show quoted textpmat> show 0x55dcb047d1d0
CODE(PP,C) at 0x55dcb047d1d0 with refcount 1
size 128 bytes
named as &Generated::__ANON__
no hekname
stash=STASH(6) at 0x55dcb0ae8510
glob=GLOB(*) at 0x55dcb0b37a40
location=t/31pad-outside.t
no scope
no padlist
no padnames_av
pad[0]=PAD(5) at 0x55dcb0ae7fb8
Show quoted textpmat> show 0x55dcb0ae7fb8
PAD(5) at 0x55dcb0ae7fb8 with refcount 1
size 104 bytes
padcv=CODE(PP,C) at 0x55dcb047d1d0
[0/@_ ]=ARRAY(0,!REAL) at 0x55dcb0a841d8
[1/$self ]=UNDEF() at 0x55dcb047d1e8
[2/@(Object::Pad/slots)]=ARRAY(0) at 0x55dcb047d290
[3/$letter ]=UNDEF() at 0x55dcb047d278
[4 ]=UNDEF() at 0x55dcb045a470
The `$letter` lexical in this method has been detached from its scope and recreated independently.
If instead we write the code as `my $code = sub { ... }` instead of method, then perl correctly captures it as expected:
Show quoted textpmat> show 0x558c82007b58
SCALAR(PV) at 0x558c82007b58 with refcount 3
size 50 bytes
PV="x"
PVLEN 1
Show quoted textpmat> identify 0x558c82007b58
SCALAR(PV) at 0x558c82007b58 is:
├─a constant of CODE() at 0x558c8188e6c8=main_cv, which is:
│ └─the main code
├─the lexical $letter at depth 1 of CODE() at 0x558c8188e6c8=main_cv, which is:
│ └─the main code
└─the lexical $letter at depth 1 of CODE(PP,C) at 0x558c818b11d0, which is:
└─(via RV) the lexical $code at depth 1 of CODE() at 0x558c8188e6c8=main_cv, which is:
└─the main code
It's already here in the `identify` output as being a captured lexical of the anon sub found in $code.
--
Paul Evans