diff --git a/phpunit/code/loop/for-loop-post-expr-opt.php b/phpunit/code/loop/for-loop-post-expr-opt.php index 1679311b..64615ddd 100644 --- a/phpunit/code/loop/for-loop-post-expr-opt.php +++ b/phpunit/code/loop/for-loop-post-expr-opt.php @@ -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]--) { } } diff --git a/phpunit/code/loop/for-loop-undefined-post-dec.php b/phpunit/code/loop/for-loop-undefined-post-dec.php new file mode 100644 index 00000000..066c84f9 --- /dev/null +++ b/phpunit/code/loop/for-loop-undefined-post-dec.php @@ -0,0 +1,7 @@ +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'); + } } diff --git a/phpunit/src/LoopControlTest.php b/phpunit/src/LoopControlTest.php index e80a0073..48acac18 100644 --- a/phpunit/src/LoopControlTest.php +++ b/phpunit/src/LoopControlTest.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', + ); + } } diff --git a/src/CompilerBase.php b/src/CompilerBase.php index cac3c1e6..bdd58a52 100644 --- a/src/CompilerBase.php +++ b/src/CompilerBase.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 diff --git a/tests/compiler/loop/for-post-expression-inc-dec.phpt b/tests/compiler/loop/for-post-expression-inc-dec.phpt new file mode 100644 index 00000000..00e3f746 --- /dev/null +++ b/tests/compiler/loop/for-post-expression-inc-dec.phpt @@ -0,0 +1,51 @@ +--TEST-- +for post-expression increment and decrement preserve runtime semantics +--FILE-- + 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)