diff --git a/examples/error/concat_void.php b/examples/error/concat_void.php new file mode 100644 index 00000000..9435ca38 --- /dev/null +++ b/examples/error/concat_void.php @@ -0,0 +1,11 @@ +parseIdentifier($expr->left); + $left = $this->parseIdentifier($expr->left); $right = $this->parseIdentifier($expr->right); - return 'php::concat(' . $left . ', ' . $right . ')'; + $leftType = $this->detectTypeOfExpr($expr->left); + $rightType = $this->detectTypeOfExpr($expr->right); + if ($leftType === self::TYPE_VOID or $rightType === self::TYPE_VOID) { + $this->fatalError($expr, 'Cannot concat void'); + } + return Symbol::concat() . '(' . $this->convertStringExpr($left) . ', ' . $this->convertStringExpr($right) . ')'; } protected function parseFor(Node\Stmt\For_ $v): string @@ -2879,7 +2884,7 @@ class CompilerBase extends \PhpAot\Core\Translator { $expr = $this->parseExpr($expr->expr); - return '!' . $expr; + return '!(' . $expr . ')'; } protected function parseWhile(Node\Stmt\While_ $v): string @@ -3305,6 +3310,15 @@ class CompilerBase extends \PhpAot\Core\Translator $type = $this->detectTypeOfExpr($arg->value); if ($argInfo->byRef) { + if ($this->isVarExpr($arg->value)) { + $var = $this->parseVariable($arg->value); + // 若参数是引用类型,可以传入未定义变量,将立即创建变量作为引用 + if (!$this->hasLocalVar($var)) { + $this->addLocalVar($var, self::TYPE_VAR); + } elseif ($this->getVarType($var) != self::TYPE_REF) { + $this->fatalError($arg, "Argument `{$argInfo->name}` must be a reference, `{$type}` given"); + } + } return $this->convertToRef($arg->value); } @@ -4407,7 +4421,7 @@ class CompilerBase extends \PhpAot\Core\Translator return $flags; } - protected function parseConstDef(mixed $v2): string + protected function parseConstDef(mixed $v2): void { foreach ($v2->consts as $const) { $name = $this->parseIdentifier($const->name); @@ -4417,8 +4431,6 @@ class CompilerBase extends \PhpAot\Core\Translator } $this->addConstant($name, $value); } - - return ''; } protected function addConstant(string $name, string $value): void diff --git a/src/Php/Preprocessor.php b/src/Php/Preprocessor.php index eb3672e3..cffc9e66 100644 --- a/src/Php/Preprocessor.php +++ b/src/Php/Preprocessor.php @@ -129,7 +129,7 @@ class Preprocessor extends CompilerBase $this->prepareClass($v); break; case 'Stmt_Function': - $this->prepareFunction($v) . PHP_EOL; + $this->prepareFunction($v); break; case 'Stmt_Use': $this->parseUse($v); @@ -202,7 +202,7 @@ class Preprocessor extends CompilerBase $this->prepareClass($v2); break; case 'Stmt_Function': - $this->prepareFunction($v2) . PHP_EOL; + $this->prepareFunction($v2); break; case 'Stmt_Use': $this->parseUse($v2); @@ -579,7 +579,7 @@ class Preprocessor extends CompilerBase if ($this->classDef->hasMethod($name)) { $this->fatalError($v, "Duplicate method `{$this->method}`"); } - $this->prepareFunction($v) . PHP_EOL; + $this->prepareFunction($v); $this->checkRequiredArgNum($name, $this->methodDef, $v); $this->classDef->addMethod($this->methodDef); } else { diff --git a/src/Php/Symbol.php b/src/Php/Symbol.php index d2ddb2e9..6ce94c11 100644 --- a/src/Php/Symbol.php +++ b/src/Php/Symbol.php @@ -25,6 +25,11 @@ class Symbol return 'php::instanceOf'; } + public static function concat(): string + { + return 'php::concat'; + } + public static function getCalledCe(): string { return CompilerBase::PREFIX . 'get_called_ce(this_)'; diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 349bea83..c40429cf 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -848,10 +848,10 @@ class Translator extends Preprocessor $cppCode .= $this->parseFunction($v) . PHP_EOL; break; case 'Stmt_Const': - $this->parseConstDef($v) . PHP_EOL; + $this->parseConstDef($v); break; case 'Stmt_Interface': - $this->parseInterface($v) . PHP_EOL; + $this->parseInterface($v); break; case 'Stmt_Nop': break; @@ -985,7 +985,7 @@ class Translator extends Preprocessor $code .= $this->parseUse($v2) . PHP_EOL; break; case 'Stmt_Interface': - $code .= $this->parseInterface($v2) . PHP_EOL; + $this->parseInterface($v2); break; default: abort($v2); @@ -1471,25 +1471,25 @@ class Translator extends Preprocessor $this->addLocalVar($tmpArrayVar, self::TYPE_ARRAY); $code = 'if (' . $obj . '.instanceOf("IteratorAggregate")) {' . PHP_EOL; - $code .= $this->getIndent() . $tmpVar . ' = ' . $obj . '.exec("getIterator");' . PHP_EOL . '}' . PHP_EOL; + $code .= $this->getIndent() . $tmpVar . ' = ' . $obj . '.call("getIterator");' . PHP_EOL . '}' . PHP_EOL; $code .= 'else if (' . $obj . '.instanceOf("Iterator")) {' . PHP_EOL; $code .= $this->getIndent() . $tmpVar . ' = ' . $obj . ';' . PHP_EOL . '}' . PHP_EOL; $code .= 'if (' . $tmpVar . ') {' . PHP_EOL; $this->indentLevel++; - $code .= $this->getIndent() . $tmpVar . '.exec("rewind");' . PHP_EOL; - $code .= $this->getIndent() . 'for (;' . $tmpVar . '.exec("valid"); ' . $tmpVar . '.exec("next")) {' . PHP_EOL; + $code .= $this->getIndent() . $tmpVar . '.call("rewind");' . PHP_EOL; + $code .= $this->getIndent() . 'for (;' . $tmpVar . '.call("valid"); ' . $tmpVar . '.call("next")) {' . PHP_EOL; $this->indentLevel++; $valueVar = $this->parseIdentifier($node->valueVar); $this->checkVar($node, $valueVar); - $code .= $this->getIndent() . ' ' . $valueVar . ' = ' . $tmpVar . '.exec("current");' . PHP_EOL; + $code .= $this->getIndent() . ' ' . $valueVar . ' = ' . $tmpVar . '.call("current");' . PHP_EOL; if ($node->keyVar) { $keyVar = $this->parseIdentifier($node->keyVar); $this->checkVar($node, $keyVar); - $code .= $this->getIndent() . ' ' . $keyVar . ' = ' . $tmpVar . '.exec("key");' . PHP_EOL; + $code .= $this->getIndent() . ' ' . $keyVar . ' = ' . $tmpVar . '.call("key");' . PHP_EOL; } $code .= $this->parseStmts($node->stmts); $code .= '}' . PHP_EOL; diff --git a/tests/aot/ref/006.phpt b/tests/aot/ref/006.phpt new file mode 100644 index 00000000..858669ee --- /dev/null +++ b/tests/aot/ref/006.phpt @@ -0,0 +1,27 @@ +--TEST-- +ref +--FILE-- +foo('hello', $class); + $this->dump($class); + } + + public function foo($name, ?string &$class) { + $class = __CLASS__; + } + + public function dump(string $class) { + var_dump($class); + } +} + +function main() +{ + $req = new Request; + $req->bar(); +} +?> +--EXPECT-- +string(7) "Request" \ No newline at end of file