From e824c5d7c0bd34d7914ad8d2c4ff5326f2309291 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Fri, 23 Jan 2026 18:28:07 +0800 Subject: [PATCH] =?UTF-8?q?fix(compiler):=20=E4=BF=AE=E5=A4=8D=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E8=B5=8B=E5=80=BC=E5=92=8C=E5=B1=9E=E6=80=A7=E8=AE=BF?= =?UTF-8?q?=E9=97=AE=E7=9A=84=E7=B1=BB=E5=9E=8B=E6=A3=80=E6=9F=A5=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加了对属性赋值操作的类型检测支持 - 实现了模运算符的类型安全处理 - 添加了布尔值转义函数 escapeBool - 修改 parsePropertyFetch 方法以支持赋值操作标识 - 优化 foreach 循环中的变量检查逻辑 - 添加引用赋值的类型验证 - 将 writeFile 方法改为公有以便外部调用 - 添加 checkVar 方法进行变量类型安全检查 - 更新测试文件中的变量命名以避免冲突 - 修复对象链接测试中的属性访问问题 --- bin/gen_stub.php | 6 ++-- src/Php/CompilerBase.php | 42 +++++++++++++++++++------ src/Php/Translator.php | 9 ++++-- tests/aot/assignment_operators.phpt | 4 +-- tests/aot/complex_array_operations.phpt | 4 +-- tests/aot/foreach.phpt | 4 +-- tests/aot/object-link.phpt | 3 +- 7 files changed, 51 insertions(+), 21 deletions(-) diff --git a/bin/gen_stub.php b/bin/gen_stub.php index 09c28178..f104ada5 100755 --- a/bin/gen_stub.php +++ b/bin/gen_stub.php @@ -35,9 +35,9 @@ const ALL_PHP_VERSION_IDS = [ // file_put_contents() but with a success message printed after saving function reportFilePutContents(string $filename, string $content): void { - if (file_put_contents($filename, $content)) { - echo "Saved $filename\n"; - } + global $translator; + $translator->writeFile($filename, $content); + echo "Saved $filename\n"; } /** diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index e456eb2f..9561e507 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -853,6 +853,8 @@ class CompilerBase extends \PhpAot\Core\Translator if (!$this->hasVar($var)) { $this->addLocalVar($var, $type); } + } elseif ($this->isPropertyFetch($left)) { + $var = $this->parsePropertyFetch($left, true); } return $var . ' = ' . $this->convertExprType($expr, $this->detectExprType($left), $this->detectExprType($right)); } @@ -935,6 +937,10 @@ class CompilerBase extends \PhpAot\Core\Translator $leftExpr = $this->convertExprType($leftExpr, $leftType, self::TYPE_INT); } + if ($op === '%' and !($leftType === self::TYPE_INT and $rightType === self::TYPE_INT)) { + return 'php::math::mod(' . $leftExpr . ', ' . $rightExpr . ')'; + } + return '((' . $leftExpr . ') ' . $op . ' (' . $rightExpr . '))'; } @@ -1936,6 +1942,11 @@ class CompilerBase extends \PhpAot\Core\Translator return addcslashes($str, "\\\"\n\r\t\v\f\0\x01..\x1f\x7f..\xff"); } + protected function escapeBool(bool $bool): string + { + return $bool ? 'true' : 'false'; + } + protected function escapeVarName(string $name): string { if (in_array($name, Constants::CPP_RESERVED_NAMES)) { @@ -2047,7 +2058,7 @@ class CompilerBase extends \PhpAot\Core\Translator return implode(PHP_EOL . $this->getIndent(), $lines); } - protected function parsePropertyFetch(Node\Expr\PropertyFetch $expr): string + protected function parsePropertyFetch(Node\Expr\PropertyFetch $expr, bool $assign = false): string { $object = $expr->var; $property = $expr->name; @@ -2057,7 +2068,8 @@ class CompilerBase extends \PhpAot\Core\Translator $id = self::PREFIX . $this->getPropertyOffset($property, $this->class, $this->namespace); } } - return $this->convertToObject($object) . '.getPropertyIndirect(' . $id . ')'; + + return $this->convertToObject($object) . '.getPropertyIndirect(' . $id . ', ' . $this->escapeBool($assign) . ')'; } protected function parseAssignOpShiftRight(Node $node): string @@ -2101,9 +2113,7 @@ class CompilerBase extends \PhpAot\Core\Translator $code = 'for (auto iter = ' . $iteratorVar . '.begin(); iter != ' . $iteratorVar . '.end(); ++iter) {' . PHP_EOL; $this->indentLevel++; if ($node->keyVar) { - if (!$this->hasVar($keyVar)) { - $this->addLocalVar($keyVar, self::TYPE_VAR); - } + $this->checkVar($node, $keyVar); $code .= $this->getIndent() . ' ' . $keyVar . ' = iter.key();' . PHP_EOL; } @@ -2116,9 +2126,7 @@ class CompilerBase extends \PhpAot\Core\Translator $code .= $this->getIndent() . "$array.offsetSet($dim, iter.value());"; } else { $valueVar = $this->parseIdentifier($node->valueVar); - if (!$this->hasVar($valueVar)) { - $this->addLocalVar($valueVar, self::TYPE_VAR); - } + $this->checkVar($node, $valueVar); $code .= $this->getIndent() . ' ' . $valueVar . ' = iter.value();' . PHP_EOL; } @@ -2394,6 +2402,11 @@ class CompilerBase extends \PhpAot\Core\Translator $var = $this->parseIdentifier($expr->var); if (!$this->hasVar($var)) { $this->addLocalVar($var, self::TYPE_REF); + } else { + $type = $this->getVarType($var); + if ($type !== self::TYPE_REF) { + $this->fatalError($expr, 'Cannot assign reference to variable of type ' . $type); + } } if ($this->isVarExpr($expr->expr)) { return $var . ' = ' . $this->parseIdentifier($expr->expr) . '.toReference()'; @@ -2668,7 +2681,7 @@ class CompilerBase extends \PhpAot\Core\Translator * @param string $content * @return void */ - protected function writeFile(string $file, string $content): void + public function writeFile(string $file, string $content): void { $dir = dirname($file); if (!is_dir($dir)) { @@ -2743,6 +2756,17 @@ class CompilerBase extends \PhpAot\Core\Translator return 'continue;'; } + protected function checkVar(NodeAbstract $node, string $name): void + { + if (!$this->hasVar($name)) { + $this->addLocalVar($name, self::TYPE_VAR); + } else { + if ($this->getVarType($name) !== self::TYPE_VAR) { + $this->fatalError($node, 'Cannot assign value to variable of type ' . $this->getVarType($name)); + } + } + } + protected function checkAccessible(ClassDef $classDef, MethodDef $methodDef): bool { // 在当前类中,允许调用所有方法 diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 81c77558..7eaf0601 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -6,6 +6,7 @@ use MJS\TopSort\Implementations\StringSort; use PhpParser\Modifiers; use PhpParser\Node; use PhpParser\Node\Stmt\Foreach_; +use PhpParser\NodeAbstract; use PhpParser\NodeTraverser; class Translator extends Preprocessor @@ -864,11 +865,15 @@ class Translator extends Preprocessor $code .= $this->getIndent() . $tmpVar . '.exec("rewind");' . PHP_EOL; $code .= $this->getIndent() . 'for (;' . $tmpVar . '.exec("valid"); ' . $tmpVar . '.exec("next")) {' . PHP_EOL; $this->indentLevel++; + $valueVar = $this->parseIdentifier($node->valueVar); - $code .= $this->getIndent() . self::TYPE_VAR . ' ' . $valueVar . ' = ' . $tmpVar . '.exec("current");' . PHP_EOL; + $this->checkVar($node, $valueVar); + + $code .= $this->getIndent() . ' ' . $valueVar . ' = ' . $tmpVar . '.exec("current");' . PHP_EOL; if ($node->keyVar) { $keyVar = $this->parseIdentifier($node->keyVar); - $code .= $this->getIndent() . self::TYPE_VAR . ' ' . $keyVar . ' = ' . $tmpVar . '.exec("key");' . PHP_EOL; + $this->checkVar($node, $keyVar); + $code .= $this->getIndent() . ' ' . $keyVar . ' = ' . $tmpVar . '.exec("key");' . PHP_EOL; } $code .= $this->parseStmts($node->stmts); $code .= '}' . PHP_EOL; diff --git a/tests/aot/assignment_operators.phpt b/tests/aot/assignment_operators.phpt index 5ad8f756..3953d8bb 100644 --- a/tests/aot/assignment_operators.phpt +++ b/tests/aot/assignment_operators.phpt @@ -61,8 +61,8 @@ var_dump($z); // Test assignment with function results $numbers = [1, 2, 3, 4, 5]; $sum = 0; -foreach ($numbers as $num) { - $sum += $num; +foreach ($numbers as $_num) { + $sum += $_num; } var_dump($sum); diff --git a/tests/aot/complex_array_operations.phpt b/tests/aot/complex_array_operations.phpt index fb9302bb..f6958186 100644 --- a/tests/aot/complex_array_operations.phpt +++ b/tests/aot/complex_array_operations.phpt @@ -115,8 +115,8 @@ function main() { // Test with array references $original = ['value' => 50]; - $ref =& $original; - $ref['value'] += 25; + $xref =& $original; + $xref['value'] += 25; var_dump($original['value']); // 75 echo "All complex array operation tests passed!\n"; diff --git a/tests/aot/foreach.phpt b/tests/aot/foreach.phpt index 1570a7f9..980334ec 100644 --- a/tests/aot/foreach.phpt +++ b/tests/aot/foreach.phpt @@ -7,8 +7,8 @@ function main() $v = 199; $arr = range(0, 99); $c = 0; - foreach ($arr as $v) { - $c += $v; + foreach ($arr as $_v) { + $c += $_v; } var_dump($c); var_dump($v); diff --git a/tests/aot/object-link.phpt b/tests/aot/object-link.phpt index 46944868..73611ba9 100644 --- a/tests/aot/object-link.phpt +++ b/tests/aot/object-link.phpt @@ -6,10 +6,11 @@ function main() { $o = new stdClass(); $o->prop = ['dim2' => ['dim3' => 'value']]; + var_dump($o->prop['dim2']['dim3']); $o->prop['dim2']['dim3'] = 'hello'; - var_dump($o->prop['dim2']['dim3']); } ?> --EXPECT-- +string(5) "value" string(5) "hello"