op.c: call class_wrap_method_body() for lexical methods

Class method bodies must be wrapped by this function, which adds the
OP_METHSTART op at the beginning, which is responsible for shifting
the `$self` lexical from the arguments array, and setting up field
bindings. This was already done for non-lexical (i.e. package) methods
but was forgotten for lexical methods, so they didn't work properly,
leading to the bug found in GH#23030 whereby the argument count in a
signatured lexical method did not take account of the `$self` argument
properly.

In addition, fields accessed by the method body would not have been
working, though originally this wasn't reported or tested either. A test
for this has also been added.
This commit is contained in:
Paul "LeoNerd" Evans 2025-02-26 17:25:05 +00:00 committed by Paul Evans
parent 42e7ab19c7
commit c3dff8a676
2 changed files with 23 additions and 1 deletions

2
op.c
View File

@ -10657,6 +10657,8 @@ Perl_newMYSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
}
if (block) {
if (CvIsMETHOD(PL_compcv))
block = class_wrap_method_body(block);
/* This makes sub {}; work as expected. */
if (block->op_type == OP_STUB) {
const line_t l = PL_parser->copline;

View File

@ -106,8 +106,10 @@ no warnings 'experimental::class';
# ->& operator can invoke methods with lexical scope
{
class Testcase8 {
field $f = "private-result";
my method priv {
return "private-result";
return $f;
}
method notpriv {
@ -134,4 +136,22 @@ no warnings 'experimental::class';
'->&m operator does not follow inheritance');
}
# lexical methods with signatures work correctly (GH#23030)
{
class Testcase9 {
field $x = 123;
my method priv ( $y ) {
return "X is $x and Y is $y for $self";
}
method test {
$self->&priv(456);
}
}
like(Testcase9->new->test, qr/^X is 123 and Y is 456 for Testcase9=OBJECT\(0x.*\)$/,
'lexical method with signature counts $self correctly');
}
done_testing;