fix(loop): preserve increment diagnostics after rewrite

master
韩天峰 2 days ago
parent 8d3d1febc2
commit 1c16639418
  1. 18
      phpunit/code/loop/for-loop-post-expr-opt.php
  2. 7
      phpunit/code/loop/for-loop-undefined-post-dec.php
  3. 7
      phpunit/code/loop/for-loop-undefined-post-inc.php
  4. 6
      phpunit/code/undefined-pre-dec.php
  5. 6
      phpunit/code/undefined-pre-inc.php
  6. 10
      phpunit/src/AssignOpTest.php
  7. 16
      phpunit/src/LoopControlTest.php
  8. 14
      src/CompilerBase.php
  9. 51
      tests/compiler/loop/for-post-expression-inc-dec.phpt

@ -58,40 +58,34 @@ class StaticCounter {
function test_property_post_inc_not_rewritten(): void {
$obj = new Counter();
for ($i = 0; $i < 10; $i++) {
$obj->value++;
for ($i = 0; $i < 10; $i++, $obj->value++) {
}
}
function test_property_post_dec_not_rewritten(): void {
$obj = new Counter();
for ($i = 0; $i < 10; $i++) {
$obj->value--;
for ($i = 0; $i < 10; $i++, $obj->value--) {
}
}
function test_static_property_post_inc_not_rewritten(): void {
for ($i = 0; $i < 10; $i++) {
StaticCounter::$count++;
for ($i = 0; $i < 10; $i++, StaticCounter::$count++) {
}
}
function test_static_property_post_dec_not_rewritten(): void {
for ($i = 0; $i < 10; $i++) {
StaticCounter::$count--;
for ($i = 0; $i < 10; $i++, StaticCounter::$count--) {
}
}
function test_array_element_post_inc_not_rewritten(): void {
$arr = [0, 0, 0];
for ($i = 0; $i < 10; $i++) {
$arr[$i % 3]++;
for ($i = 0; $i < 10; $i++, $arr[$i % 3]++) {
}
}
function test_array_element_post_dec_not_rewritten(): void {
$arr = [10, 10, 10];
for ($i = 0; $i < 10; $i++) {
$arr[$i % 3]--;
for ($i = 0; $i < 10; $i++, $arr[$i % 3]--) {
}
}

@ -0,0 +1,7 @@
<?php
function main(): void
{
for (; false; $i--) {
}
}

@ -0,0 +1,7 @@
<?php
function main(): void
{
for (; false; $i++) {
}
}

@ -0,0 +1,6 @@
<?php
function main(): void
{
--$value;
}

@ -0,0 +1,6 @@
<?php
function main(): void
{
++$value;
}

@ -26,4 +26,14 @@ class AssignOpTest extends \BaseTest
{
$this->exec('Cannot use -- on php::Decimal', 'decimal-pre-dec.php');
}
public function testPreIncrementUndefinedVar(): void
{
$this->exec('The variable `$value` is undefined', 'undefined-pre-inc.php');
}
public function testPreDecrementUndefinedVar(): void
{
$this->exec('The variable `$value` is undefined', 'undefined-pre-dec.php');
}
}

@ -61,4 +61,20 @@ class LoopControlTest extends \BaseTest
$this->assertMatchesRegularExpression('/\.item\([^)]+\)[^;]*\+\+/', $cpp);
$this->assertMatchesRegularExpression('/\.item\([^)]+\)[^;]*--/', $cpp);
}
public function testForLoopUndefinedPostIncrementKeepsCompilerDiagnostic(): void
{
$this->exec(
'The variable `$i` is undefined',
'loop/for-loop-undefined-post-inc.php',
);
}
public function testForLoopUndefinedPostDecrementKeepsCompilerDiagnostic(): void
{
$this->exec(
'The variable `$i` is undefined',
'loop/for-loop-undefined-post-dec.php',
);
}
}

@ -3350,8 +3350,11 @@ class CompilerBase implements PropertyAccessContext
if ($type === Type::BIGINT || $type === Type::DECIMAL || $type === Type::BIGFLOAT) {
$this->fatalError($expr, 'Cannot use ++ on ' . $type . '. Use += 1 instead (Big* types are immutable).');
}
$result = '++' . $this->parseWritableIdentifier($expr->var);
return $result;
$var = $this->parseWritableIdentifier($expr->var);
if ($this->isVarExpr($expr->var) && !$this->hasVar($var)) {
$this->errorUndefinedVariable($expr->var);
}
return '++' . $var;
}
/**
@ -3789,8 +3792,11 @@ class CompilerBase implements PropertyAccessContext
if ($type === Type::BIGINT || $type === Type::DECIMAL || $type === Type::BIGFLOAT) {
$this->fatalError($expr, 'Cannot use -- on ' . $type . '. Use -= 1 instead (Big* types are immutable).');
}
$result = '--' . $this->parseWritableIdentifier($expr->var);
return $result;
$var = $this->parseWritableIdentifier($expr->var);
if ($this->isVarExpr($expr->var) && !$this->hasVar($var)) {
$this->errorUndefinedVariable($expr->var);
}
return '--' . $var;
}
protected function parsePrint(Expr\Print_ $expr): string

@ -0,0 +1,51 @@
--TEST--
for post-expression increment and decrement preserve runtime semantics
--FILE--
<?php
final class LoopCounter
{
public int $value = 0;
public static int $staticValue = 10;
}
function ascending(mixed $start): void
{
for ($i = $start; $i < 3; $i++) {
echo $i;
}
echo ':', $i, "\n";
}
function descending(mixed $start): void
{
for ($i = $start; $i > 0; $i--) {
echo $i;
}
echo ':', $i, "\n";
}
function main(): void
{
ascending(0);
descending(3);
$object = new LoopCounter();
$values = [0];
for (
$i = 0;
$i < 3;
$i++, $object->value++, LoopCounter::$staticValue--, $values[0]++
) {
}
var_dump($i, $object->value, LoopCounter::$staticValue, $values[0]);
}
?>
--EXPECT--
012:3
321:0
int(3)
int(3)
int(7)
int(3)
Loading…
Cancel
Save