fix(aot): 修复数组复合赋值表达式返回值

修复复合赋值运算符(如 +=)在数组元素上使用时返回值错误的问题。
之前代码使用了存储变量而非读取变量进行运算,并且未正确返回运算结果。
现在通过使用读取变量参与计算并返回临时变量值来修复此问题,
同时添加了 FFI 和数组相关的测试用例。
pull/14/head
韩天峰 2 months ago
parent 4ceb938009
commit 6afb8e3689
  1. 9
      src/Php/Parser/AssignOpTrait.php
  2. 9
      tests/aot/array/array_assignment_operators.phpt
  3. 31
      tests/aot/ffi/addr-cast-sizeof.phpt
  4. 32
      tests/aot/ffi/array-assignment.phpt
  5. 34
      tests/aot/ffi/array-compound-assignment.phpt
  6. 31
      tests/aot/ffi/array-scalar-read.phpt
  7. 34
      tests/aot/ffi/basic.phpt
  8. 50
      tests/aot/ffi/cdef-declarations.phpt
  9. 32
      tests/aot/ffi/struct-fields.phpt

@ -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)) {

@ -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!
int(15)
int(15)
All array assignment tests passed!

@ -0,0 +1,31 @@
--TEST--
FFI addr cast typeof and sizeof
--EXTENSIONS--
ffi
--ENV--
USE_ZEND_ALLOC=0
--INI--
ffi.enable=1
--FILE--
<?php
function main(): void
{
$value = FFI::new("int");
$value->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)

@ -0,0 +1,32 @@
--TEST--
FFI multidimensional array assignment keeps CData containers
--EXTENSIONS--
ffi
--ENV--
USE_ZEND_ALLOC=0
--INI--
ffi.enable=1
--FILE--
<?php
function main(): void
{
$ffi = FFI::cdef();
$matrix = $ffi->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)

@ -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--
<?php
function main(): void
{
$array = FFI::new("int[3]");
$array[0] = 10;
$array[1] = 20;
$array[2] = 30;
$result = ($array[0] += 5);
var_dump($array[0]);
var_dump($result);
$array[1] *= 2;
var_dump($array[1]);
$array[2] -= $array[0];
var_dump($array[2]);
}
?>
--EXPECT--
int(15)
int(15)
int(40)
int(15)

@ -0,0 +1,31 @@
--TEST--
FFI array element scalar read matches PHP
--EXTENSIONS--
ffi
--ENV--
USE_ZEND_ALLOC=0
--INI--
ffi.enable=1
--FILE--
<?php
function main(): void
{
$array = FFI::new("int[3]");
$array[0] = 10;
$array[1] = 20;
$array[2] = 30;
var_dump($array[0]);
var_dump($array[0] + $array[1]);
var_dump($array[0] === 10);
var_dump($array[0] == 10);
var_dump(is_int($array[0]));
}
?>
--EXPECT--
int(10)
int(30)
bool(true)
bool(true)
bool(true)

@ -0,0 +1,34 @@
--TEST--
FFI basic CData and libc call
--EXTENSIONS--
ffi
--ENV--
USE_ZEND_ALLOC=0
--INI--
ffi.enable=1
--SKIPIF--
<?php
try {
FFI::cdef("int abs(int);", "libc.so.6");
} catch (Throwable $e) {
die("skip FFI::cdef is not available: " . $e->getMessage());
}
?>
--FILE--
<?php
function main(): void
{
$array = FFI::new("int[3]");
$array[0] = 10;
$array[1] = 20;
$array[2] = 30;
var_dump($array instanceof FFI\CData);
$libc = FFI::cdef("int abs(int);", "libc.so.6");
var_dump($libc->abs(-42));
}
?>
--EXPECT--
bool(true)
int(42)

@ -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--
<?php
try {
FFI::cdef("int abs(int);", "libc.so.6");
} catch (Throwable $e) {
die("skip FFI::cdef is not available: " . $e->getMessage());
}
?>
--FILE--
<?php
function main(): void
{
$ffi = FFI::cdef(<<<'CDEF'
typedef struct point {
int x;
int y;
} point_t;
enum color {
COLOR_RED = 1,
COLOR_GREEN = 2
};
int abs(int);
CDEF
, "libc.so.6");
$point = FFI::new("struct point { int x; int y; }");
$color = FFI::new("enum color { COLOR_RED = 1, COLOR_GREEN = 2 }");
var_dump($point instanceof FFI\CData);
var_dump($color instanceof FFI\CData);
var_dump(FFI::sizeof($point));
var_dump($ffi->abs(-7));
}
?>
--EXPECT--
bool(true)
bool(true)
int(8)
int(7)

@ -0,0 +1,32 @@
--TEST--
FFI struct field write and address
--EXTENSIONS--
ffi
--ENV--
USE_ZEND_ALLOC=0
--INI--
ffi.enable=1
--FILE--
<?php
function main(): void
{
$node = FFI::new(<<<'CDEF'
struct node {
int id;
int value;
}
CDEF);
$node->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)
Loading…
Cancel
Save