TypePHP 编译器
https://swoole.com/aot/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
4.4 KiB
122 lines
4.4 KiB
<?php
|
|
|
|
namespace TypePhp\Tests;
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
use PhpParser\Node;
|
|
use TypePhp\CompilerTest;
|
|
use TypePhp\Diagnostics\DiagnosticReporter;
|
|
use TypePhp\Exception\TestError;
|
|
|
|
/**
|
|
* Constant integer arithmetic overflow emits compile-time warnings and folds
|
|
* to the PHP float result in non-native mode.
|
|
*/
|
|
class ConstantArithmeticOverflowTest extends TestCase
|
|
{
|
|
public function testOverflowingConstantArithmeticEmitsWarning(): void
|
|
{
|
|
$reporter = $this->compileWithReporter();
|
|
|
|
$overflowWarnings = array_values(array_filter(
|
|
$reporter->warnings,
|
|
fn (string $message): bool => str_contains($message, 'Constant integer arithmetic overflows int64')
|
|
));
|
|
$this->assertCount(3, $overflowWarnings);
|
|
$this->assertStringContainsString('9223372036854775807 + 1', $overflowWarnings[0]);
|
|
$this->assertStringContainsString('folding to PHP float result', $overflowWarnings[0]);
|
|
}
|
|
|
|
public function testNonOverflowingConstantArithmeticDoesNotWarn(): void
|
|
{
|
|
$reporter = $this->compileWithReporter();
|
|
|
|
foreach ($reporter->warnings as $message) {
|
|
$this->assertStringNotContainsString('1 + 2', $message);
|
|
}
|
|
}
|
|
|
|
public function testNativeModeRejectsConstantUndefinedBehavior(): void
|
|
{
|
|
$cases = [
|
|
'constant-overflow-native-add.php' => '9223372036854775807 + 1',
|
|
'constant-overflow-native-sub.php' => '-9223372036854775808 - 1',
|
|
'constant-overflow-native-mul.php' => '9223372036854775807 * 2',
|
|
'constant-overflow-native-div.php' => '-9223372036854775808 / -1',
|
|
'constant-overflow-native-mod.php' => '-9223372036854775808 % -1',
|
|
'constant-overflow-native-neg.php' => 'Negating PHP_INT_MIN',
|
|
'constant-overflow-native-nested-add.php' => '9223372036854775807 + 1',
|
|
'constant-overflow-native-nested-div.php' => '-9223372036854775808 / -1',
|
|
'constant-overflow-native-nested-mod.php' => '-9223372036854775808 % -1',
|
|
'constant-overflow-native-nested-zero.php' => 'Constant division or modulo by zero',
|
|
'constant-overflow-native-div-subtree.php' => '9223372036854775807 + 2',
|
|
];
|
|
|
|
foreach ($cases as $file => $expectedMessage) {
|
|
try {
|
|
$this->compileNativeFile($file);
|
|
$this->fail("Expected native constant overflow in {$file} to be rejected");
|
|
} catch (TestError $e) {
|
|
$this->assertStringContainsString($expectedMessage, $e->getMessage());
|
|
}
|
|
}
|
|
|
|
$this->compileNativeFile('constant-overflow-native-ok.php');
|
|
$this->compileNativeFile('constant-overflow-native-nonconstant.php');
|
|
$this->addToAssertionCount(1);
|
|
}
|
|
|
|
/**
|
|
* @return object{warnings: list<string>}
|
|
*/
|
|
private function compileWithReporter(): object
|
|
{
|
|
global $translator;
|
|
$compiler = CompilerTest::create(ROOT_PATH);
|
|
$translator = $compiler;
|
|
$reporter = new class implements DiagnosticReporter {
|
|
/** @var list<string> */
|
|
public array $warnings = [];
|
|
|
|
public function fatal(string $message): never
|
|
{
|
|
throw new TestError($message);
|
|
}
|
|
|
|
public function warning(Node $node, string $file, string $message): void
|
|
{
|
|
$this->warnings[] = $message;
|
|
}
|
|
};
|
|
$compiler->setDiagnosticReporter($reporter);
|
|
|
|
$testFile = __DIR__ . '/../code/constant-overflow-warning.php';
|
|
$compiler->addFiles([$testFile]);
|
|
$compiler->prepareFile($testFile);
|
|
$compiler->convertFile($testFile);
|
|
|
|
return $reporter;
|
|
}
|
|
|
|
private function compileNativeFile(string $file): void
|
|
{
|
|
global $translator;
|
|
$compiler = CompilerTest::create(ROOT_PATH);
|
|
$translator = $compiler;
|
|
$compiler->setDiagnosticReporter(new class implements DiagnosticReporter {
|
|
public function fatal(string $message): never
|
|
{
|
|
throw new TestError($message);
|
|
}
|
|
|
|
public function warning(Node $node, string $file, string $message): void
|
|
{
|
|
}
|
|
});
|
|
|
|
$testFile = __DIR__ . '/../code/' . $file;
|
|
$compiler->addFiles([$testFile]);
|
|
$compiler->prepareFile($testFile);
|
|
$compiler->convertFile($testFile);
|
|
}
|
|
}
|
|
|