From 6afb8e3689428612712dbe5af166c116fb87a7ff Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Tue, 7 Jul 2026 14:44:10 +0800 Subject: [PATCH] =?UTF-8?q?fix(aot):=20=E4=BF=AE=E5=A4=8D=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E5=A4=8D=E5=90=88=E8=B5=8B=E5=80=BC=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8F=E8=BF=94=E5=9B=9E=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复复合赋值运算符(如 +=)在数组元素上使用时返回值错误的问题。 之前代码使用了存储变量而非读取变量进行运算,并且未正确返回运算结果。 现在通过使用读取变量参与计算并返回临时变量值来修复此问题, 同时添加了 FFI 和数组相关的测试用例。 --- src/Php/Parser/AssignOpTrait.php | 9 ++-- .../aot/array/array_assignment_operators.phpt | 9 +++- tests/aot/ffi/addr-cast-sizeof.phpt | 31 ++++++++++++ tests/aot/ffi/array-assignment.phpt | 32 ++++++++++++ tests/aot/ffi/array-compound-assignment.phpt | 34 +++++++++++++ tests/aot/ffi/array-scalar-read.phpt | 31 ++++++++++++ tests/aot/ffi/basic.phpt | 34 +++++++++++++ tests/aot/ffi/cdef-declarations.phpt | 50 +++++++++++++++++++ tests/aot/ffi/struct-fields.phpt | 32 ++++++++++++ 9 files changed, 257 insertions(+), 5 deletions(-) create mode 100644 tests/aot/ffi/addr-cast-sizeof.phpt create mode 100644 tests/aot/ffi/array-assignment.phpt create mode 100644 tests/aot/ffi/array-compound-assignment.phpt create mode 100644 tests/aot/ffi/array-scalar-read.phpt create mode 100644 tests/aot/ffi/basic.phpt create mode 100644 tests/aot/ffi/cdef-declarations.phpt create mode 100644 tests/aot/ffi/struct-fields.phpt diff --git a/src/Php/Parser/AssignOpTrait.php b/src/Php/Parser/AssignOpTrait.php index 992a688b..23c8de34 100644 --- a/src/Php/Parser/AssignOpTrait.php +++ b/src/Php/Parser/AssignOpTrait.php @@ -386,18 +386,19 @@ trait AssignOpTrait $tmpVar = $this->genTmpVarName(); $this->addLocalVar($tmpVar, $rightType); $dim = $this->parseIdentifier($node->var->dim); + $readVar = $this->parseArrayDimFetch($node->var, false); $binaryOp = $this->removeAssignOp($op); if ($binaryOp === '.') { $this->context->beforeStmtLines[] = "{$tmpVar} = php::concat(" . - $this->convertVarType($tmpVar, $var) . ', ' . + $this->convertVarType($tmpVar, $readVar) . ', ' . $this->convertExprType($expr, $type, $rightType) . ');'; } elseif ($type === self::TYPE_BIGINT || $type === self::TYPE_DECIMAL || $type === self::TYPE_BIGFLOAT) { - $bigAssign = $this->parseBigAssignOpExpr($var, $type, $expr, $rightType, $binaryOp, $node->var, $node->expr); + $bigAssign = $this->parseBigAssignOpExpr($readVar, $type, $expr, $rightType, $binaryOp, $node->var, $node->expr); $this->context->beforeStmtLines[] = "{$tmpVar} = {$bigAssign};"; } else { $this->context->beforeStmtLines[] = "{$tmpVar} = " . - $this->convertVarType($tmpVar, $var) . ' ' . + $this->convertVarType($tmpVar, $readVar) . ' ' . $binaryOp . ' ' . $this->convertExprType($expr, $type, $rightType) . ';'; } @@ -405,7 +406,7 @@ trait AssignOpTrait if ($this->isVarExpr($node->var->var) && $node->var->var->name === 'GLOBALS') { return $var . ' = ' . $tmpVar; } - return $this->parseArrayDimStore($node->var->var, $dim, $tmpVar); + return '(' . $this->parseArrayDimStore($node->var->var, $dim, $tmpVar) . ', ' . $tmpVar . ')'; } if ($this->isPropertyFetch($node->var) and !$this->isNativePropertyAccess($node->var)) { diff --git a/tests/aot/array/array_assignment_operators.phpt b/tests/aot/array/array_assignment_operators.phpt index 5d245dde..1461d64f 100644 --- a/tests/aot/array/array_assignment_operators.phpt +++ b/tests/aot/array/array_assignment_operators.phpt @@ -95,6 +95,11 @@ $seqArray['counter'] -= 3; $seqArray['counter'] /= 7; var_dump($seqArray['counter']); // 1 (7*2-3=7, then 7/7=1) +$exprResult = ['value' => 10]; +$compoundResult = ($exprResult['value'] += 5); +var_dump($exprResult['value']); +var_dump($compoundResult); + echo "All array assignment tests passed!\n"; ?> --EXPECT-- @@ -121,4 +126,6 @@ string(33) "nested array assignment operators" int(150) int(15) int(1) -All array assignment tests passed! \ No newline at end of file +int(15) +int(15) +All array assignment tests passed! diff --git a/tests/aot/ffi/addr-cast-sizeof.phpt b/tests/aot/ffi/addr-cast-sizeof.phpt new file mode 100644 index 00000000..bb17e0bd --- /dev/null +++ b/tests/aot/ffi/addr-cast-sizeof.phpt @@ -0,0 +1,31 @@ +--TEST-- +FFI addr cast typeof and sizeof +--EXTENSIONS-- +ffi +--ENV-- +USE_ZEND_ALLOC=0 +--INI-- +ffi.enable=1 +--FILE-- +cdata = 123; + + $addr = FFI::addr($value); + $ptr = FFI::cast("int*", $addr); + $type = FFI::typeof($value); + + var_dump($addr instanceof FFI\CData); + var_dump($ptr instanceof FFI\CData); + var_dump($type instanceof FFI\CType); + var_dump(FFI::sizeof($type)); +} +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +int(4) diff --git a/tests/aot/ffi/array-assignment.phpt b/tests/aot/ffi/array-assignment.phpt new file mode 100644 index 00000000..7ae29fb5 --- /dev/null +++ b/tests/aot/ffi/array-assignment.phpt @@ -0,0 +1,32 @@ +--TEST-- +FFI multidimensional array assignment keeps CData containers +--EXTENSIONS-- +ffi +--ENV-- +USE_ZEND_ALLOC=0 +--INI-- +ffi.enable=1 +--FILE-- +new("int[2][2]"); + $row = $ffi->new("int[2]"); + $row[0] = 11; + $row[1] = 22; + $matrix[1] = $row; + + var_dump($matrix instanceof FFI\CData); + var_dump($row instanceof FFI\CData); + var_dump(FFI::sizeof($matrix)); + var_dump(FFI::sizeof($row)); +} +?> +--EXPECT-- +bool(true) +bool(true) +int(16) +int(8) diff --git a/tests/aot/ffi/array-compound-assignment.phpt b/tests/aot/ffi/array-compound-assignment.phpt new file mode 100644 index 00000000..1777b932 --- /dev/null +++ b/tests/aot/ffi/array-compound-assignment.phpt @@ -0,0 +1,34 @@ +--TEST-- +FFI array element compound assignment reads scalar value +--EXTENSIONS-- +ffi +--ENV-- +USE_ZEND_ALLOC=0 +--INI-- +ffi.enable=1 +--FILE-- + +--EXPECT-- +int(15) +int(15) +int(40) +int(15) diff --git a/tests/aot/ffi/array-scalar-read.phpt b/tests/aot/ffi/array-scalar-read.phpt new file mode 100644 index 00000000..19f1b4cd --- /dev/null +++ b/tests/aot/ffi/array-scalar-read.phpt @@ -0,0 +1,31 @@ +--TEST-- +FFI array element scalar read matches PHP +--EXTENSIONS-- +ffi +--ENV-- +USE_ZEND_ALLOC=0 +--INI-- +ffi.enable=1 +--FILE-- + +--EXPECT-- +int(10) +int(30) +bool(true) +bool(true) +bool(true) diff --git a/tests/aot/ffi/basic.phpt b/tests/aot/ffi/basic.phpt new file mode 100644 index 00000000..5313d6c7 --- /dev/null +++ b/tests/aot/ffi/basic.phpt @@ -0,0 +1,34 @@ +--TEST-- +FFI basic CData and libc call +--EXTENSIONS-- +ffi +--ENV-- +USE_ZEND_ALLOC=0 +--INI-- +ffi.enable=1 +--SKIPIF-- +getMessage()); +} +?> +--FILE-- +abs(-42)); +} +?> +--EXPECT-- +bool(true) +int(42) diff --git a/tests/aot/ffi/cdef-declarations.phpt b/tests/aot/ffi/cdef-declarations.phpt new file mode 100644 index 00000000..0ea3e614 --- /dev/null +++ b/tests/aot/ffi/cdef-declarations.phpt @@ -0,0 +1,50 @@ +--TEST-- +FFI cdef declarations create structs enums and functions +--EXTENSIONS-- +ffi +--ENV-- +USE_ZEND_ALLOC=0 +--INI-- +ffi.enable=1 +--SKIPIF-- +getMessage()); +} +?> +--FILE-- +abs(-7)); +} +?> +--EXPECT-- +bool(true) +bool(true) +int(8) +int(7) diff --git a/tests/aot/ffi/struct-fields.phpt b/tests/aot/ffi/struct-fields.phpt new file mode 100644 index 00000000..76f28f7d --- /dev/null +++ b/tests/aot/ffi/struct-fields.phpt @@ -0,0 +1,32 @@ +--TEST-- +FFI struct field write and address +--EXTENSIONS-- +ffi +--ENV-- +USE_ZEND_ALLOC=0 +--INI-- +ffi.enable=1 +--FILE-- +id = 123; + $node->value = 456; + $addr = FFI::addr($node); + + var_dump($node instanceof FFI\CData); + var_dump($addr instanceof FFI\CData); + var_dump(FFI::sizeof($node)); +} +?> +--EXPECTF-- +bool(true) +bool(true) +int(%d)