diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 4aeb0691..4592cdd1 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -849,6 +849,7 @@ class CompilerBase extends \PhpAot\Core\Translator if (!$this->isReturnStmtInLastLine($v->stmts)) { $stmts .= $this->genReturnCode(); } + $this->functionDef->completed = true; } catch (Skip) { $this->climate->cyan('Skip function ' . $name); } @@ -1719,9 +1720,10 @@ class CompilerBase extends \PhpAot\Core\Translator protected function resetReturnType(Node\Stmt\Return_ $node, string $type): void { + $oriType = $this->functionDef->returnType; $this->functionDef->returnType = $type; // 返回值变更,需要重新解析 - $this->climate->cyan('Return type changed at line ' . $node->getLine() . ', retrying...'); + $this->climate->cyan("Return type changed ($oriType -> $type) at line {$node->getLine()} retrying..."); throw new Redo(); } @@ -1792,9 +1794,12 @@ class CompilerBase extends \PhpAot\Core\Translator $method = $this->parseIdentifier($expr->name); $nativeFunc = $this->findNativeMethod($expr, $object, $method); if ($nativeFunc) { - return $this->nativeFunctions[$nativeFunc]->returnType; - } - if ($this->isTypedObject($object)) { + $funcDef = $this->nativeFunctions[$nativeFunc]; + // 此函数尚未完成解析,仅经过初步的预处理,无法获得准确的返回值类型 + if ($funcDef->completed) { + return $funcDef->returnType; + } + } elseif ($this->isTypedObject($object)) { return $this->detectMethodCallReturnType($this->getObjectType($object), $method); } } @@ -3579,9 +3584,13 @@ class CompilerBase extends \PhpAot\Core\Translator protected function detectFuncCallReturnType(string $name): string { - $returnType = Reflection::getFunctionReturnType($name); - if ($returnType) { - return $this->getTypeFromZendType($returnType); + if ($this->isInternalFunction($name)) { + $returnType = Reflection::getFunctionReturnType($name); + // void 类型将被忽略,类型推测仅用于赋值操作的右值,即使返回值为 void , 赋值操作也应该继续运行,右值会被当做 null + // 例如 $a = var_dump('hello'); 虽然 var_dump 返回值为 void ,但是 $a 的类型是 mixed,值为 null + if ($returnType and $returnType !== 'void') { + return $this->getTypeFromZendType($returnType); + } } return self::TYPE_VAR; } @@ -3589,7 +3598,7 @@ class CompilerBase extends \PhpAot\Core\Translator protected function detectMethodCallReturnType(string $class, string $method): string { $returnType = Reflection::getMethodReturnType($class, $method); - if ($returnType) { + if ($returnType and $returnType !== 'void') { return $this->getTypeFromZendType($returnType); } return self::TYPE_VAR; @@ -3978,8 +3987,9 @@ class CompilerBase extends \PhpAot\Core\Translator goto _to_object; } } else { + $ex = $this->parseIdentifier($expr->expr); _to_object: - $ex = $this->convertObjectExpr($expr->expr); + $ex = $this->convertObjectExpr($ex); } return 'php::throwException(' . $ex . ')'; } @@ -4208,7 +4218,7 @@ class CompilerBase extends \PhpAot\Core\Translator $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)); + $this->fatalError($node, 'Cannot assign value to variable $' . $name . ' of type ' . $this->getVarType($name)); } } } diff --git a/src/Php/Entity/FunctionDef.php b/src/Php/Entity/FunctionDef.php index a0d7edb2..b596b61c 100644 --- a/src/Php/Entity/FunctionDef.php +++ b/src/Php/Entity/FunctionDef.php @@ -23,6 +23,7 @@ class FunctionDef public string $params = ''; public string $namespace = ''; public bool $method = false; + public bool $completed = false; public function __construct(string $name, string $returnType, string $namespace = '') { diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 248df334..cdbb7ffb 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -865,7 +865,7 @@ class Translator extends Preprocessor $extends = $class->extends; } - $fullName = $this->getNamespacedClassName($this->class); + $fullName = ltrim($this->namespace . '\\' . $this->class, '\\'); if ($this->hasNativeClass($fullName)) { $this->classDef = $this->getClassDef($fullName); } else { diff --git a/tests/aot/return-value.phpt b/tests/aot/return-value.phpt new file mode 100644 index 00000000..651046de --- /dev/null +++ b/tests/aot/return-value.phpt @@ -0,0 +1,13 @@ +--TEST-- +object link operator +--FILE-- + +--EXPECT-- +string(3) "foo" +NULL \ No newline at end of file