fix(compiler): 修复抽象类和接口的类型处理逻辑

- 移除对抽象类和接口参数类型的限制检查
- 简化对象类型推断逻辑,统一处理所有类类型
- 更新 addObject 方法,阻止为抽象类、接口、内部类创建实例
- 修正参数类型处理中的重复对象添加问题
pull/1/head
韩天峰 3 months ago
parent ee81d116ef
commit 71627fd920
  1. 19
      src/Php/CompilerBase.php
  2. 24
      tests/aot/class/abstract-class-method.phpt
  3. 14
      tests/aot/class/abstract-class.inc

@ -1113,10 +1113,7 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
foreach ($this->functionDef->argInfoList as $argInfo) { foreach ($this->functionDef->argInfoList as $argInfo) {
$this->addArgument($argInfo->name, $argInfo->type); $this->addArgument($argInfo->name, $argInfo->type);
if ($argInfo->class if ($argInfo->class) {
and !$this->isAbstractClass($argInfo->class)
and !$this->hasInterface($argInfo->class)
and !$this->isInternalClass($argInfo->class)) {
$this->addObject($argInfo->name, $argInfo->class); $this->addObject($argInfo->name, $argInfo->class);
} }
} }
@ -1656,10 +1653,7 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($rightClass) { if ($rightClass) {
if (!$this->hasVar($var)) { if (!$this->hasVar($var)) {
$this->addLocalVar($var, self::TYPE_OBJECT); $this->addLocalVar($var, self::TYPE_OBJECT);
// TODO 返回值类型是一个接口,只能作为 var 变量,无法作为 TypedObject $this->addObject($var, $rightClass);
if (!$this->hasInterface($rightClass) and !$this->isAbstractClass($rightClass)) {
$this->addObject($var, $rightClass);
}
} elseif ($this->isTypedObject($var)) { } elseif ($this->isTypedObject($var)) {
$leftClass = $this->getObjectType($var); $leftClass = $this->getObjectType($var);
// 对象的类不一致,不能互相赋值,必须使用 objval() 对齐类型 // 对象的类不一致,不能互相赋值,必须使用 objval() 对齐类型
@ -2202,8 +2196,12 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function addObject(string $name, string $class): void protected function addObject(string $name, string $class): void
{ {
if ($this->hasInterface($class) or $this->isAbstractClass($class)) { // 接口、抽象类、内部类、非原生类,无法作为 TypedObject 使用
$this->error("Cannot create an instance of abstract/interface `$class`"); if ($this->hasInterface($class) or
$this->isInternalClass($class) or
$this->isAbstractClass($class) or
!$this->hasClass($class)) {
return;
} }
$this->context->objects[$name] = $class; $this->context->objects[$name] = $class;
} }
@ -2671,7 +2669,6 @@ class CompilerBase extends \PhpAot\Core\Translator
$type = self::TYPE_VAR; $type = self::TYPE_VAR;
} }
if ($class and !$this->hasInterface($class) and !$this->isAbstractClass($class)) { if ($class and !$this->hasInterface($class) and !$this->isAbstractClass($class)) {
$this->addObject($var, $class);
$argInfo->class = $class; $argInfo->class = $class;
} }
return $type; return $type;

@ -0,0 +1,24 @@
--TEST--
abstract class and abstract method
--FILE--
<?php
namespace {
use App1\Dog;
use App1\Animal;
function foo(Animal $animal) {
$rs = $animal->speak();
var_dump($rs);
}
function main() {
include __DIR__ . "/abstract-class.inc";
$dog = new Dog("Buddy");
foo($dog);
echo "done\n";
}
}
?>
--EXPECT--
string(4) "woof"
done

@ -0,0 +1,14 @@
<?php
namespace App1 {
interface Speakable {
public function speak(): string;
}
abstract class Animal implements Speakable {
protected string $name;
}
class Dog extends Animal {
public function speak(): string {
return "woof";
}
}
}
Loading…
Cancel
Save