From af0e30fa70dc040d582c6b84f83ab66c7d6667db Mon Sep 17 00:00:00 2001 From: PurHur Date: Fri, 24 Jul 2026 07:08:09 +0000 Subject: [PATCH] =?UTF-8?q?Language:=20gate=20pipe=20operator=20|>=20on=20?= =?UTF-8?q?PROFILE=E2=89=A58.5=20(#22792)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit |> is PHP 8.5-only in Zend; PROFILE=8.4 and the reference profile must parse-error like php-src. Keep desugar under PHP_COMPILER_PROFILE=8.5. Co-authored-by: Cursor --- lib/Ast/PipeOperatorDesugar.php | 4 ++-- lib/CompilerVersion.php | 8 ++++---- lib/PipeOperatorSyntaxRejector.php | 4 ++-- test/compliance/JITTest.php | 4 +++- test/compliance/VMTest.php | 4 +++- .../language/pipe_operator_forward_profile.phpt | 10 +++++----- .../pipe_operator_profile84_reject.phpt | 16 ++++++++++++++++ .../pipe_operator_reference_profile.phpt | 2 +- test/unit/CompilerVersionGateTest.php | 17 ++++++++++++++++- test/unit/PipeOperatorReferenceProfileTest.php | 2 +- test/unit/PipeOperatorSyntaxRejectorTest.php | 6 +++--- test/unit/PipeOperatorTest.php | 2 +- 12 files changed, 57 insertions(+), 22 deletions(-) create mode 100644 test/compliance/cases/language/pipe_operator_profile84_reject.phpt diff --git a/lib/Ast/PipeOperatorDesugar.php b/lib/Ast/PipeOperatorDesugar.php index 4b6a558703b..68f7647171e 100644 --- a/lib/Ast/PipeOperatorDesugar.php +++ b/lib/Ast/PipeOperatorDesugar.php @@ -7,10 +7,10 @@ use PHPCompiler\CompilerVersion; /** - * Desugar PHP 8.4+ pipe operator (|>) before nikic/php-parser (#3243, #7219). + * Desugar PHP 8.5+ pipe operator (|>) before nikic/php-parser (#3243, #7219, #22792). * * Lowering matches Zend: $lhs |> $callable(...) becomes $callable($lhs, ...). - * php-src: Zend/zend_compile.c pipe expression handling. + * php-src: Zend/zend_compile.c pipe expression handling (PHP 8.5+). */ final class PipeOperatorDesugar { diff --git a/lib/CompilerVersion.php b/lib/CompilerVersion.php index 1b91f82fda9..820ae3b2dd7 100644 --- a/lib/CompilerVersion.php +++ b/lib/CompilerVersion.php @@ -895,14 +895,14 @@ public static function supportsExitFunctionForm(): bool } /** - * PHP 8.4+ pipe operator (|>) — Zend/zend_language_parser.y (#7219, #12424, #16675). + * PHP 8.5+ pipe operator (|>) — Zend/zend_language_parser.y (#7219, #12424, #16675, #22792). * - * Gated on stable 8.4.0 / {@see languageProfileVersion()} so 8.4.0-dev reference profile - * rejects |> like Zend 8.2. Forward profile via `PHP_COMPILER_PROFILE=8.4` enables desugar. + * Withheld on reference / PROFILE=8.4 (matches Zend 8.2 / 8.4 parse error). Enable via + * stable 8.5.0+ or explicit `PHP_COMPILER_PROFILE=8.5` forward profile. */ public static function supportsPipeOperator(): bool { - return version_compare(self::languageProfileVersion(), '8.4.0', '>='); + return version_compare(self::languageProfileVersion(), '8.5.0', '>='); } /** diff --git a/lib/PipeOperatorSyntaxRejector.php b/lib/PipeOperatorSyntaxRejector.php index ff843cbecff..315e08e95ff 100644 --- a/lib/PipeOperatorSyntaxRejector.php +++ b/lib/PipeOperatorSyntaxRejector.php @@ -8,10 +8,10 @@ use PHPCompiler\Compiler\CompileFatal; /** - * Reject PHP 8.4+ pipe operator (|>) on the Zend 8.2 reference profile (#12424, #18007). + * Reject PHP 8.5+ pipe operator (|>) below PROFILE=8.5 (#12424, #18007, #22792). * * Must run before {@see Ast\PipeOperatorDesugar} so pipe syntax is not lowered into valid PHP. - * php-src: Zend/zend_language_parser.y pipe expression grammar. + * php-src: Zend/zend_language_parser.y pipe expression grammar (PHP 8.5+). */ final class PipeOperatorSyntaxRejector { diff --git a/test/compliance/JITTest.php b/test/compliance/JITTest.php index 3ba79eef9a3..b1462fdf680 100755 --- a/test/compliance/JITTest.php +++ b/test/compliance/JITTest.php @@ -1245,7 +1245,8 @@ public static function providePHPTests(): \Generator && !str_contains($name, 'try_catch_else_reference_profile')) { continue; } - // 8.4-target reject gate; skipped when pipe operator enabled (#12424, #18007). + // 8.5-target reject gate; skipped when pipe operator enabled (#12424, #18007, #22792). + // profile84_reject uses --ENV-- PROFILE=8.4 — always include. if (CompilerVersion::supportsPipeOperator() && str_contains($name, 'pipe_operator_reference_profile')) { continue; @@ -1253,6 +1254,7 @@ public static function providePHPTests(): \Generator if (!CompilerVersion::supportsPipeOperator() && str_contains($name, 'pipe_operator') && !str_contains($name, 'pipe_operator_reference_profile') + && !str_contains($name, 'pipe_operator_profile84_reject') && !str_contains($name, 'pipe_operator_forward_profile')) { continue; } diff --git a/test/compliance/VMTest.php b/test/compliance/VMTest.php index 4e7edc50464..4b71486531b 100755 --- a/test/compliance/VMTest.php +++ b/test/compliance/VMTest.php @@ -1187,7 +1187,8 @@ public static function providePHPTests(): \Generator && !str_contains($name, 'try_catch_else_reference_profile')) { continue; } - // 8.4-target reject gate; skipped when pipe operator enabled (#12424, #18007). + // 8.5-target reject gate; skipped when pipe operator enabled (#12424, #18007, #22792). + // profile84_reject uses --ENV-- PROFILE=8.4 — always include. if (CompilerVersion::supportsPipeOperator() && str_contains($name, 'pipe_operator_reference_profile')) { continue; @@ -1195,6 +1196,7 @@ public static function providePHPTests(): \Generator if (!CompilerVersion::supportsPipeOperator() && str_contains($name, 'pipe_operator') && !str_contains($name, 'pipe_operator_reference_profile') + && !str_contains($name, 'pipe_operator_profile84_reject') && !str_contains($name, 'pipe_operator_forward_profile')) { continue; } diff --git a/test/compliance/cases/language/pipe_operator_forward_profile.phpt b/test/compliance/cases/language/pipe_operator_forward_profile.phpt index 54d35dd7bc8..6bdd20b11ca 100644 --- a/test/compliance/cases/language/pipe_operator_forward_profile.phpt +++ b/test/compliance/cases/language/pipe_operator_forward_profile.phpt @@ -1,19 +1,19 @@ --TEST-- -Language: pipe operator |> on forward profile PHP 8.4 (#16675, Zend/zend_language_parser.y) +Language: pipe operator |> on forward profile PHP 8.5 (#16675, #22792, Zend/zend_language_parser.y) --SKIPIF-- --ENV-- -PHP_COMPILER_PROFILE=8.4 +PHP_COMPILER_PROFILE=8.5 --FILE-- rejected on PROFILE=8.4 (#22792, Zend/zend_language_parser.y) +--SKIPIF-- + +--ENV-- +PHP_COMPILER_PROFILE=8.4 +--FILE-- + strtoupper(...); +--EXPECT_EXIT-- +255 diff --git a/test/compliance/cases/language/pipe_operator_reference_profile.phpt b/test/compliance/cases/language/pipe_operator_reference_profile.phpt index 07101d774f0..5fc1036d2a9 100644 --- a/test/compliance/cases/language/pipe_operator_reference_profile.phpt +++ b/test/compliance/cases/language/pipe_operator_reference_profile.phpt @@ -6,7 +6,7 @@ if (!class_exists('PHPCompiler\\CompilerVersion')) { require __DIR__ . '/../../../../vendor/autoload.php'; } if (PHPCompiler\CompilerVersion::supportsPipeOperator()) { - die('skip pipe operator enabled on PHP 8.4.0+ target'); + die('skip pipe operator enabled on PHP 8.5.0+ target'); } ?> --FILE-- diff --git a/test/unit/CompilerVersionGateTest.php b/test/unit/CompilerVersionGateTest.php index d2f61c2851a..5da578301dc 100644 --- a/test/unit/CompilerVersionGateTest.php +++ b/test/unit/CompilerVersionGateTest.php @@ -1245,10 +1245,25 @@ public function testSupportsPipeOperatorFalseOnReferenceProfile(): void $this->assertFalse(CompilerVersion::supportsPipeOperator()); } - public function testSupportsPipeOperatorTrueWhenProfile84(): void + public function testSupportsPipeOperatorFalseWhenProfile84(): void { $prev = getenv('PHP_COMPILER_PROFILE'); putenv('PHP_COMPILER_PROFILE=8.4'); + try { + $this->assertFalse(CompilerVersion::supportsPipeOperator()); + } finally { + if (false === $prev) { + putenv('PHP_COMPILER_PROFILE'); + } else { + putenv('PHP_COMPILER_PROFILE='.$prev); + } + } + } + + public function testSupportsPipeOperatorTrueWhenProfile85(): void + { + $prev = getenv('PHP_COMPILER_PROFILE'); + putenv('PHP_COMPILER_PROFILE=8.5'); try { $this->assertTrue(CompilerVersion::supportsPipeOperator()); } finally { diff --git a/test/unit/PipeOperatorReferenceProfileTest.php b/test/unit/PipeOperatorReferenceProfileTest.php index db167be2441..e9ca0ea15f9 100644 --- a/test/unit/PipeOperatorReferenceProfileTest.php +++ b/test/unit/PipeOperatorReferenceProfileTest.php @@ -18,7 +18,7 @@ public function testSupportsPipeOperatorFalseOnReferenceProfile(): void public function testDesugarNoOpWhenPipeDisabled(): void { if (CompilerVersion::supportsPipeOperator()) { - $this->markTestSkipped('pipe operator enabled on PHP 8.4.0+ target'); + $this->markTestSkipped('pipe operator enabled on PHP 8.5.0+ target'); } $src = ' fn ($v) => $v * 2;'; $this->assertSame($src, PipeOperatorDesugar::desugar($src)); diff --git a/test/unit/PipeOperatorSyntaxRejectorTest.php b/test/unit/PipeOperatorSyntaxRejectorTest.php index e4f35a3fe72..4a1455a08cd 100644 --- a/test/unit/PipeOperatorSyntaxRejectorTest.php +++ b/test/unit/PipeOperatorSyntaxRejectorTest.php @@ -14,7 +14,7 @@ final class PipeOperatorSyntaxRejectorTest extends TestCase public function testRejectsPipeOnReferenceProfile(): void { if (CompilerVersion::supportsPipeOperator()) { - self::markTestSkipped('pipe operator enabled on PHP 8.4.0+ target'); + self::markTestSkipped('pipe operator enabled on PHP 8.5.0+ target'); } $this->expectException(CompileFatal::class); @@ -26,7 +26,7 @@ public function testRejectsPipeOnReferenceProfile(): void public function testReferenceProfileSyntaxErrorLine(): void { if (CompilerVersion::supportsPipeOperator()) { - self::markTestSkipped('pipe operator enabled on PHP 8.4.0+ target'); + self::markTestSkipped('pipe operator enabled on PHP 8.5.0+ target'); } $error = PipeOperatorDesugar::referenceProfileSyntaxError(<<<'PHP' @@ -43,7 +43,7 @@ public function testReferenceProfileSyntaxErrorLine(): void public function testNoOpWithoutPipeToken(): void { if (CompilerVersion::supportsPipeOperator()) { - self::markTestSkipped('pipe operator enabled on PHP 8.4.0+ target'); + self::markTestSkipped('pipe operator enabled on PHP 8.5.0+ target'); } $code = ') VM desugar (#3243, #7219). */ +/** PHP 8.5+ pipe operator (|>) VM desugar (#3243, #7219, #22792). */ final class PipeOperatorTest extends TestCase { protected function setUp(): void