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
pull/43/head
韩天峰 4 weeks ago
parent 9a7de8ee31
commit 8f2e63b9f7
  1. 16
      phpunit/code/bool-literal-identical.php
  2. 20
      phpunit/src/OperatorTest.php
  3. 18
      src/Parser/BinaryOpTrait.php
  4. 34
      tests/compiler/operator/bool-literal-identical.phpt

@ -0,0 +1,16 @@
<?php
function bool_literal_identical(bool $pjax): array
{
return [
true === $pjax,
$pjax === true,
false !== $pjax,
$pjax !== false,
];
}
function dynamic_bool_literal_identical(mixed $value): bool
{
return true === $value;
}

@ -2,6 +2,26 @@
class OperatorTest extends \BaseTest
{
public function testBooleanLiteralStrictComparisonUsesNativeBoolOperands(): void
{
global $translator;
$compiler = \TypePhp\CompilerTest::create(ROOT_PATH);
$translator = $compiler;
$testFile = __DIR__ . '/../code/bool-literal-identical.php';
$compiler->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');

@ -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, '&&');

@ -0,0 +1,34 @@
--TEST--
Boolean literals on either side of strict comparisons
--FILE--
<?php
function compare_bool_literal(bool $pjax): void
{
var_dump(true === $pjax);
var_dump($pjax === true);
var_dump(false === $pjax);
var_dump($pjax === false);
var_dump(true !== $pjax);
var_dump($pjax !== true);
}
function main(): void
{
compare_bool_literal(true);
compare_bool_literal(false);
}
?>
--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)
Loading…
Cancel
Save