refactor(php): 重构对象属性赋值检查逻辑并优化循环变量检测

- 提取公共的对象属性赋值验证方法 assertCanAssignObjectProperty
- 统一处理对象属性和静态属性的赋值检查逻辑
- 在类型检查中增加对抽象类、接口和未知类的处理
- 优化循环变量依赖检测算法,改进错误处理流程
- 移除静态编译阶段无法确定类型的严格检查,改为运行时处理
- 修复循环变量优化器中的依赖检测中断逻辑
pull/1/head
韩天峰 3 months ago
parent 51772c1e27
commit 9b1477e13b
  1. 66
      src/Php/CompilerBase.php
  2. 7
      src/Php/Optimizer/LoopVarOptimizer.php

@ -3569,55 +3569,15 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function assertCanAssignObjectProp(Expr\PropertyFetch $left, Expr $right): void
{
if (!$left->hasAttribute('nativePropertyDef')) {
return;
}
/** @var PropertyDef $def */
$def = $left->getAttribute('nativePropertyDef');
if ($this->isNull($right)) {
if ($this->isFixedObjectProp($def)) {
$this->fatalError(
$left,
"Cannot assign null to object property `{$this->parseIdentifier($left->name)}` of fixed type `{$def->type}`"
);
}
return;
}
if ($def->type !== self::TYPE_OBJECT) {
return;
}
$rightType = $this->detectTypeOfExpr($right);
if ($rightType !== self::TYPE_VAR && $rightType !== self::TYPE_OBJECT) {
$this->fatalError(
$left,
"Cannot assign value of type `{$rightType}` to object property `{$this->parseIdentifier($left->name)}` of type `{$def->type}`"
);
}
if ($def->class === '') {
return;
}
$rightClass = $this->detectClassOfExpr($right);
if ($rightClass === '') {
$this->fatalError(
$left,
"Cannot assign object of unknown class to object property `{$this->parseIdentifier($left->name)}` of class `{$def->class}`"
);
}
if ($rightClass !== $def->class) {
$this->fatalError(
$left,
"Cannot assign object of class `{$rightClass}` to object property `{$this->parseIdentifier($left->name)}` of class `{$def->class}`"
);
}
$this->assertCanAssignObjectProperty($left, $right, 'object property');
}
protected function assertCanAssignStaticProp(Expr\StaticPropertyFetch $left, Expr $right): void
{
$this->assertCanAssignObjectProperty($left, $right, 'static property');
}
private function assertCanAssignObjectProperty(NodeAbstract $left, Expr $right, string $label): void
{
if (!$left->hasAttribute('nativePropertyDef')) {
return;
@ -3631,7 +3591,7 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($this->isFixedObjectProp($def)) {
$this->fatalError(
$left,
"Cannot assign null to static property `{$propName}` of fixed type `{$def->type}`"
"Cannot assign null to {$label} `{$propName}` of fixed type `{$def->type}`"
);
}
return;
@ -3645,25 +3605,23 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($rightType !== self::TYPE_VAR && $rightType !== self::TYPE_OBJECT) {
$this->fatalError(
$left,
"Cannot assign value of type `{$rightType}` to static property `{$propName}` of type `{$def->type}`"
"Cannot assign value of type `{$rightType}` to {$label} `{$propName}` of type `{$def->type}`"
);
}
if ($def->class === '') {
if ($def->class === '' or $this->isAbstractClass($def->class) or $this->isInterface($def->class) or !$this->hasClass($def->class)) {
return;
}
$rightClass = $this->detectClassOfExpr($right);
// TODO 静态编译阶段无法获得准确的类型,需要在运行时检查
if ($rightClass === '') {
$this->fatalError(
$left,
"Cannot assign object of unknown class to static property `{$propName}` of class `{$def->class}`"
);
return;
}
if ($rightClass !== $def->class) {
$this->fatalError(
$left,
"Cannot assign object of class `{$rightClass}` to static property `{$propName}` of class `{$def->class}`"
"Cannot assign object of class `{$rightClass}` to {$label} `{$propName}` of class `{$def->class}`"
);
}
}

@ -55,12 +55,17 @@ trait LoopVarOptimizer
if ($this->loopVarHasUnsafeUsage($varName, $stmts, $candidate['allowed'] ?? [])) {
continue;
}
$depFailed = false;
foreach ($candidate['deps'] ?? [] as $depName => $_) {
if (!$this->isLoopSsaVarStable($depName)
|| $this->loopVarHasUnsafeUsage($depName, $stmts, $candidates[$depName]['allowed'] ?? [])) {
continue 2;
$depFailed = true;
break;
}
}
if ($depFailed) {
continue;
}
$this->context->localVars[$escapedName] = self::TYPE_INT;
}
}

Loading…
Cancel
Save