From 8f2e63b9f71c07f56458df9a249d19718bf31351 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Fri, 31 Jul 2026 16:38:32 +0800 Subject: [PATCH] fix(parser): handle native boolean literals in strict comparisons - Added nativeBoolLiteral method to convert PHP boolean literals to C++ bool - Updated parseCompareExpr to use native boolean literals for bool type - Ensured strict comparisons between booleans use true/false instead of php::true_/php::false_ - Added test case for boolean literal identical comparisons - Created compiler test to verify native boolean operand usage - Added test file with boolean literal comparison examples --- phpunit/code/bool-literal-identical.php | 16 +++++++++ phpunit/src/OperatorTest.php | 20 +++++++++++ src/Parser/BinaryOpTrait.php | 18 ++++++++++ .../operator/bool-literal-identical.phpt | 34 +++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 phpunit/code/bool-literal-identical.php create mode 100644 tests/compiler/operator/bool-literal-identical.phpt diff --git a/phpunit/code/bool-literal-identical.php b/phpunit/code/bool-literal-identical.php new file mode 100644 index 00000000..7bd3d9ea --- /dev/null +++ b/phpunit/code/bool-literal-identical.php @@ -0,0 +1,16 @@ +addFiles([$testFile]); + $compiler->prepareFile($testFile); + $cppFile = $compiler->convertFile($testFile); + $cpp = file_get_contents($cppFile); + + $this->assertStringContainsString('true == pjax', $cpp); + $this->assertStringContainsString('pjax == true', $cpp); + $this->assertStringContainsString('false == pjax', $cpp); + $this->assertStringContainsString('pjax == false', $cpp); + $this->assertStringNotContainsString('php::true_ == pjax', $cpp); + $this->assertStringNotContainsString('php::false_ == pjax', $cpp); + $this->assertStringContainsString('php::same(php::true_, value)', $cpp); + } + public function testLiteralIntDivideByZeroDoesNotCompile(): void { $this->exec('Cannot divide or modulo by zero', 'divide-by-zero-int.php'); diff --git a/src/Parser/BinaryOpTrait.php b/src/Parser/BinaryOpTrait.php index 83332cb4..feae8dcb 100644 --- a/src/Parser/BinaryOpTrait.php +++ b/src/Parser/BinaryOpTrait.php @@ -414,11 +414,29 @@ trait BinaryOpTrait return null; } if ($leftType === $rightType) { + if ($leftType === Type::BOOL) { + $cppLeft = $this->nativeBoolLiteral($astLeft) ?? $cppLeft; + $cppRight = $this->nativeBoolLiteral($astRight) ?? $cppRight; + } return $cppLeft . ' == ' . $cppRight; } return 'false'; } + /** + * Strict comparisons between native booleans must use C++ bool literals. + * parseCompareExpr() normally emits php::true_/php::false_ Variants because + * dynamic comparisons need zvals, but those wrappers are incorrect once + * optimizeIdenticalOp() selects a direct primitive comparison. + */ + private function nativeBoolLiteral(NodeAbstract $expr): ?string + { + if (!$this->isScalarBool($expr)) { + return null; + } + return strcasecmp($expr->name->toString(), 'true') === 0 ? 'true' : 'false'; + } + protected function parseBinaryOpLogicalAnd(Expr\BinaryOp\LogicalAnd|Expr\BinaryOp\BooleanAnd $expr): string { return $this->parseShortCircuitLogicalOp($expr->left, $expr->right, '&&'); diff --git a/tests/compiler/operator/bool-literal-identical.phpt b/tests/compiler/operator/bool-literal-identical.phpt new file mode 100644 index 00000000..d73ec833 --- /dev/null +++ b/tests/compiler/operator/bool-literal-identical.phpt @@ -0,0 +1,34 @@ +--TEST-- +Boolean literals on either side of strict comparisons +--FILE-- + +--EXPECT-- +bool(true) +bool(true) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(true) +bool(true) +bool(true) +bool(true)