From 8684d1652c7a42b2f59348111c2aef2e6eff4aed Mon Sep 17 00:00:00 2001 From: Yurun Date: Fri, 3 Jul 2026 15:48:50 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(compiler):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E5=92=8C=E6=95=B0=E7=BB=84=E5=85=83=E7=B4=A0?= =?UTF-8?q?=E4=BD=9C=E4=B8=BA=E8=B5=8B=E5=80=BC=E8=A1=A8=E8=BE=BE=E5=BC=8F?= =?UTF-8?q?=E5=8F=B3=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Php/CompilerBase.php | 4 +-- src/Php/Parser/AssignOpTrait.php | 6 ++-- tests/aot/basic/multi-var-assign.phpt | 50 +++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 tests/aot/basic/multi-var-assign.phpt diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index c216b715..34957002 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -1375,8 +1375,8 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont return $this->parseConstFetch($expr); case 'Expr_Assign': case 'Expr_AssignRef': - if (!$this->isVarExpr($expr->var)) { - $this->fatalError($expr, 'When an assignment expression serves as an rvalue, it must be an assignment of a variable'); + if (!$this->isVarExpr($expr->var) && !$this->isPropertyFetch($expr->var) && !$this->isArrayDimFetch($expr->var)) { + $this->fatalError($expr, 'When an assignment expression serves as an rvalue, it must be an assignment of a variable, property, or array element'); } return $this->parseExpr($expr); default: diff --git a/src/Php/Parser/AssignOpTrait.php b/src/Php/Parser/AssignOpTrait.php index 021d655e..24661283 100644 --- a/src/Php/Parser/AssignOpTrait.php +++ b/src/Php/Parser/AssignOpTrait.php @@ -85,13 +85,13 @@ trait AssignOpTrait $chain = array_reverse($chain); $list = []; - $list[] = $this->getIndent() . $tmpVar . ' = ' . $this->parseExpr($next); + $list[] = $tmpVar . ' = ' . $this->parseExpr($next); $rightVar = new Variable($tmpVar); foreach ($chain as $var) { - $list[] = $this->getIndent() . $this->parseAssignFinally($var, $rightVar); + $list[] = $this->parseAssignFinally($var, $rightVar); } - return implode(";\n" . $this->getIndent(), $list); + return '(' . implode(', ', $list) . ')'; } protected function parseAssign(Expr\Assign $v): string diff --git a/tests/aot/basic/multi-var-assign.phpt b/tests/aot/basic/multi-var-assign.phpt new file mode 100644 index 00000000..d2a10236 --- /dev/null +++ b/tests/aot/basic/multi-var-assign.phpt @@ -0,0 +1,50 @@ +--TEST-- +Multi-variable assignment: property assignment as rvalue in constructor argument expression +--FILE-- +value = new Test2($this->arr[0] = $this->value2 = 123); + var_dump($this->value2, $this->arr); + $this->value = new Test2($this->arr[0] = $this->value3 = $this->value2 = 456); + var_dump($this->value2, $this->value3, $this->arr); + } +} + +function main() +{ + new Test; +} +?> +--EXPECT-- +int(123) +int(123) +array(1) { + [0]=> + int(123) +} +int(456) +int(456) +int(456) +array(1) { + [0]=> + int(456) +} From c59184bed7afbce62ed3932074333d75c1f015ff Mon Sep 17 00:00:00 2001 From: Yurun Date: Fri, 3 Jul 2026 16:15:44 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(compiler):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=95=B0=E7=BB=84=E5=92=8C=E5=B1=9E=E6=80=A7=E6=95=B0=E7=BB=84?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E5=90=8C=E6=97=B6=E9=93=BE=E5=BC=8F=E8=B5=8B?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Php/CompilerBase.php | 5 +++ src/Php/Parser/AssignOpTrait.php | 2 + tests/aot/basic/multi-var-assign-chained.phpt | 45 +++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 tests/aot/basic/multi-var-assign-chained.phpt diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 34957002..bbf507fa 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -2304,6 +2304,11 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont protected function detectVarType($var): string { + // Unwrap ArrayDimFetch to get the underlying variable type; + // the dim/index does not affect the base variable's type. + if ($var instanceof Expr\ArrayDimFetch) { + return $this->detectVarType($var->var); + } $name = $this->parseIdentifier($var); if ($this->isStdContainer($name)) { return self::TYPE_ARRAY; diff --git a/src/Php/Parser/AssignOpTrait.php b/src/Php/Parser/AssignOpTrait.php index 24661283..efb309fe 100644 --- a/src/Php/Parser/AssignOpTrait.php +++ b/src/Php/Parser/AssignOpTrait.php @@ -272,6 +272,8 @@ trait AssignOpTrait return $this->parseStdContainerAssign($left, $right); } return $this->parseAssignArrayDim($left, $right); + } elseif ($this->isArrayDimFetch($left) and $this->isPropertyFetch($left->var)) { + return $this->parseAssignPropertyArrayDim($left, $right); } if ($propertyWriteTarget !== null) { diff --git a/tests/aot/basic/multi-var-assign-chained.phpt b/tests/aot/basic/multi-var-assign-chained.phpt new file mode 100644 index 00000000..ab8cf6ec --- /dev/null +++ b/tests/aot/basic/multi-var-assign-chained.phpt @@ -0,0 +1,45 @@ +--TEST-- +Chained assignment with array append ([]), property write, and variable write as rvalue inside constructor argument +--FILE-- +arr[] = $arr[] = $this->value = $value = 1); + var_dump($this->value, $value, $this->arr, $arr); + } +} + +function main() +{ + new Test; +} +?> +--EXPECT-- +int(1) +int(1) +int(1) +array(1) { + [0]=> + int(1) +} +array(2) { + [0]=> + int(0) + [1]=> + int(1) +}