fix(compiler): resolve bitwise not operation on class constants in AOT compilation

- Updated CompilerBase.php to use convertIntExpr for bitwise not operations on variables
- Modified gen_stub.php to always use var_export for default value conversion
- Enhanced object_property test to follow strict type checking with TypeError handling
- Added native property test for bitwise not class constant assignments
- Updated Translator.php to return raw values instead of CValue wrappers for constants
- Improved documentation consistency across project overview files
- Added strict types declaration to property assignment test cases
pull/16/head
韩天峰 2 months ago
parent 631a1ef6b2
commit d2b7a36430
  1. 2
      .github/copilot-instructions.md
  2. 2
      CLAUDE.md
  3. 13
      phpunit/src/NativePropertyTest.php
  4. 2
      src/CompilerBase.php
  5. 8
      src/Translator.php
  6. 4
      src/gen_stub.php
  7. 11
      tests/aot/object_property/native-int-property-assign.phpt

@ -2,7 +2,7 @@
## Project overview
TypePHP is an ahead-of-time compiler that translates PHP source into C++, then compiles and links it into a native binary or a PHP extension. The primary entrypoint is `tpc`, which boots `src/compiler.php`; that drives `TypePhp\Translator` through a fixed pipeline:
TypePHP is a PHP native compilation project. Its `tpc` command is TypePHP Compiler (AOT), which translates PHP source into C++, then compiles and links it into a native binary or a PHP extension. The primary entrypoint boots `src/compiler.php`; that drives `TypePhp\Translator` through a fixed pipeline:
1. `prepare()` scans files, parses ASTs, collects symbols, and topologically sorts PHP files by cross-file symbol usage.
2. `convert()` turns PHP ASTs into generated `.cc` files while passing through native source files (`.cpp`, `.c`, `.s`, `.m`, `.mm`).

@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Project Overview
TypePHP is an AOT (Ahead-of-Time) compiler that translates PHP source code to C++, then compiles it with GCC/Clang/MSVC into native binaries. It supports Linux (primary), macOS, and Windows.
TypePHP is a PHP native compilation project. Its `tpc` command is TypePHP Compiler (AOT), which translates PHP source code to C++, then compiles it with GCC/Clang/MSVC into native binaries. It supports Linux (primary), macOS, and Windows.
**Prerequisites**: PHP 8.2+, GCC 9+ (C++17), CMake 3.24+. The `swoole/phpx` extension must be compiled (see README.md).

@ -58,6 +58,19 @@ class NativePropertyTest extends \BaseTest
$this->assertStringNotContainsString('box.attr(php_get_prop(0, _literal_strings[0], 0, _literal_strings[1]), true) +=', $code);
}
public function testNativeIntPropertyAssignOpConvertsBitwiseNotClassConst(): void
{
try {
$outputFile = $this->compileNativeProperty('native-property-assign-op-class-const.php');
} catch (TestError $e) {
$this->fail($e->getMessage());
}
$code = file_get_contents($outputFile);
$this->assertStringContainsString('php_aot_static_int_ref(this_.attr(', $code);
$this->assertStringContainsString('&= (~php::toInt(php::constant(', $code);
}
public function testNativePropertyWriteConvertsOnlyWhenTypesDiffer(): void
{
try {

@ -4423,7 +4423,7 @@ class CompilerBase implements PropertyAccessContext
return 'php::BigInt::bitNot(' . $this->parseExpr($expr->expr) . ')';
}
$var = $this->parseIdentifier($expr->expr);
return '~' . $var;
return '~' . $this->convertIntExpr($var);
}
protected function parseIf(Node\Stmt\If_ $v): string

@ -39,7 +39,7 @@ use Symfony\Component\Yaml\Yaml;
class Translator extends Preprocessor
{
public const string VERSION = '0.3.0';
public const string APP_NAME = 'TypePHP';
public const string APP_NAME = 'TypePHP Compiler (AOT)';
protected string $targetName = 'app';
protected array $sourceDirs = [];
protected bool $verbose = false;
@ -1881,12 +1881,12 @@ CODE;
$nativeConst = $this->findNativeClassConst($expr, $class, $name);
if ($nativeConst and $expr->hasAttribute('nativeConst')) {
$constDef = $expr->getAttribute('nativeConst');
return $this->genCValue($constDef->valueExpr->value);
return $constDef->valueExpr->value;
}
if ($this->isInternalClass($class)) {
$constName = $class . '::' . $name;
if (defined($constName)) {
return $this->genCValue(constant($constName));
return constant($constName);
}
}
// Resolve enum case references. Enum cases are runtime objects; their
@ -1897,7 +1897,7 @@ CODE;
$classDef = $this->getClass($class);
if ($classDef->enum && array_key_exists($name, $classDef->enumCases)) {
$caseValue = $classDef->enumCases[$name];
return $this->genCValue($caseValue ?? $name);
return $caseValue ?? $name;
}
}
$this->fatalError($expr, "Class constant `{$class}::{$name}` not found");

@ -5019,9 +5019,7 @@ function parseFunctionLike(
if ($param->default instanceof Expr\ClassConstFetch && $param->default->class->toLowerString() === "self") {
$defaultValue = getTranslator()->getClassConstValue($func, $name->className->name, $param->default->name->name);
if (!is_string($defaultValue)) {
$defaultValue = var_export($defaultValue, true);
}
$defaultValue = var_export($defaultValue, true);
} else {
$defaultValue = $param->default ? $prettyPrinter->prettyPrintExpr($param->default) : null;
}

@ -1,7 +1,8 @@
--TEST--
Native int property assignment converts RHS without explicit cast
Native int property assignment follows strict property type rules
--FILE--
<?php
declare(strict_types=1);
class GridSize
{
public int $size = 0;
@ -41,7 +42,12 @@ function main(): void
$gi = new GridItem();
$gi->colStart = $idx % $numCols;
$gi->colEnd = $gi->colStart + 1;
$gi->rowStart = $idx / $numCols;
try {
$gi->rowStart = $idx / $numCols;
} catch (TypeError $e) {
var_dump($e->getMessage());
}
$gi->rowStart = intdiv($idx, $numCols);
$gi->rowEnd = $gi->rowStart + 1;
$gi->w = $cols[$gi->colStart]->size;
$gi->h = $gi->rowStart < count($rows) ? $rows[$gi->rowStart]->size : 50;
@ -53,6 +59,7 @@ function main(): void
}
?>
--EXPECT--
string(63) "Cannot assign float to property GridItem::$rowStart of type int"
int(2)
int(3)
int(1)

Loading…
Cancel
Save