From f2dfd5debf73336a7d5c7071b42d43db975470b9 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sun, 10 Nov 2024 15:09:45 +0100 Subject: [PATCH] Revert "Improve `for` loop initial statement scope pollution" This reverts commit c55aa0586bf08b8e029576ba4a78782418b4a932. --- src/Analyser/MutatingScope.php | 62 ---------- src/Analyser/NodeScopeResolver.php | 2 +- .../Analyser/ForLoopNoScopePollutionTest.php | 36 ------ .../data/for-loop-no-scope-pollution.php | 107 ------------------ .../Analyser/forLoopNoScopePollution.neon | 2 - tests/PHPStan/Analyser/nsrt/for-loop.php | 107 ------------------ .../Variables/DefinedVariableRuleTest.php | 9 -- .../PHPStan/Rules/Variables/data/bug-9550.php | 32 ------ 8 files changed, 1 insertion(+), 356 deletions(-) delete mode 100644 tests/PHPStan/Analyser/ForLoopNoScopePollutionTest.php delete mode 100644 tests/PHPStan/Analyser/data/for-loop-no-scope-pollution.php delete mode 100644 tests/PHPStan/Analyser/forLoopNoScopePollution.neon delete mode 100644 tests/PHPStan/Analyser/nsrt/for-loop.php delete mode 100644 tests/PHPStan/Rules/Variables/data/bug-9550.php diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 3993085894..5659a107bc 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -4900,68 +4900,6 @@ public function processAlwaysIterableForeachScopeWithoutPollute(self $finalScope ); } - public function processAlwaysIterableForScopeWithoutPollute(self $finalScope, self $initScope): self - { - $expressionTypes = $this->expressionTypes; - $initScopeExpressionTypes = $initScope->expressionTypes; - foreach ($finalScope->expressionTypes as $variableExprString => $variableTypeHolder) { - if (!isset($expressionTypes[$variableExprString])) { - if (isset($initScopeExpressionTypes[$variableExprString])) { - $expressionTypes[$variableExprString] = ExpressionTypeHolder::createMaybe($variableTypeHolder->getExpr(), $variableTypeHolder->getType()); - continue; - } - - $expressionTypes[$variableExprString] = $variableTypeHolder; - continue; - } - - $expressionTypes[$variableExprString] = new ExpressionTypeHolder( - $variableTypeHolder->getExpr(), - $variableTypeHolder->getType(), - $variableTypeHolder->getCertainty()->and($expressionTypes[$variableExprString]->getCertainty()), - ); - } - - $nativeTypes = $this->nativeExpressionTypes; - $initScopeNativeExpressionTypes = $initScope->nativeExpressionTypes; - foreach ($finalScope->nativeExpressionTypes as $variableExprString => $variableTypeHolder) { - if (!isset($nativeTypes[$variableExprString])) { - if (isset($initScopeNativeExpressionTypes[$variableExprString])) { - $nativeTypes[$variableExprString] = ExpressionTypeHolder::createMaybe($variableTypeHolder->getExpr(), $variableTypeHolder->getType()); - continue; - } - - $nativeTypes[$variableExprString] = $variableTypeHolder; - continue; - } - - $nativeTypes[$variableExprString] = new ExpressionTypeHolder( - $variableTypeHolder->getExpr(), - $variableTypeHolder->getType(), - $variableTypeHolder->getCertainty()->and($nativeTypes[$variableExprString]->getCertainty()), - ); - } - - return $this->scopeFactory->create( - $this->context, - $this->isDeclareStrictTypes(), - $this->getFunction(), - $this->getNamespace(), - $expressionTypes, - $nativeTypes, - $this->conditionalExpressions, - $this->inClosureBindScopeClasses, - $this->anonymousFunctionReflection, - $this->inFirstLevelStatement, - [], - [], - [], - $this->afterExtractCall, - $this->parentScope, - $this->nativeTypesPromoted, - ); - } - public function generalizeWith(self $otherScope): self { $variableTypeHolders = $this->generalizeVariableTypeHolders( diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 31dde8718b..1a6a069d28 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -1410,7 +1410,7 @@ private function processStmtNode( } } else { if (!$this->polluteScopeWithLoopInitialAssignments) { - $finalScope = $scope->processAlwaysIterableForScopeWithoutPollute($finalScope, $initScope); + $finalScope = $finalScope->mergeWith($scope); } } diff --git a/tests/PHPStan/Analyser/ForLoopNoScopePollutionTest.php b/tests/PHPStan/Analyser/ForLoopNoScopePollutionTest.php deleted file mode 100644 index 9b07f9ab2b..0000000000 --- a/tests/PHPStan/Analyser/ForLoopNoScopePollutionTest.php +++ /dev/null @@ -1,36 +0,0 @@ -> */ - public function dataFileAsserts(): iterable - { - yield from $this->gatherAssertTypes(__DIR__ . '/data/for-loop-no-scope-pollution.php'); - } - - /** - * @dataProvider dataFileAsserts - * @param mixed ...$args - */ - public function testFileAsserts( - string $assertType, - string $file, - ...$args, - ): void - { - $this->assertFileAsserts($assertType, $file, ...$args); - } - - public static function getAdditionalConfigFiles(): array - { - return [ - __DIR__ . '/forLoopNoScopePollution.neon', - ]; - } - -} diff --git a/tests/PHPStan/Analyser/data/for-loop-no-scope-pollution.php b/tests/PHPStan/Analyser/data/for-loop-no-scope-pollution.php deleted file mode 100644 index e7c0bef9ff..0000000000 --- a/tests/PHPStan/Analyser/data/for-loop-no-scope-pollution.php +++ /dev/null @@ -1,107 +0,0 @@ -', $i); - assertNativeType('int<10, max>', $i); - assertVariableCertainty(TrinaryLogic::createMaybe(), $i); - - assertType('int', $j); - assertNativeType('int', $j); - assertVariableCertainty(TrinaryLogic::createYes(), $j); - - assertType('int<0, 1>', $a); - assertNativeType('int', $a); - assertVariableCertainty(TrinaryLogic::createYes(), $a); - - assertType('int<0, 1>', $b); - assertNativeType('int', $b); - assertVariableCertainty(TrinaryLogic::createYes(), $b); - - assertType('int<0, 1>', $c); - assertNativeType('int', $c); - assertVariableCertainty(TrinaryLogic::createYes(), $c); - } - - /** @param int $b */ - public function loopThatMightIterateAtLeastOnce(int $a, $b): void - { - $j = 0; - for ($i = 0, $j = 10; $i < rand(0, 1); $i++, $j--) { - $a = rand(0, 1); - $b = rand(0, 1); - $c = rand(0, 1); - } - - assertType('int<0, max>', $i); - assertNativeType('int<0, max>', $i); - assertVariableCertainty(TrinaryLogic::createMaybe(), $i); - - assertType('int', $j); - assertNativeType('int', $j); - assertVariableCertainty(TrinaryLogic::createYes(), $j); - - assertType('int', $a); - assertNativeType('int', $a); - assertVariableCertainty(TrinaryLogic::createYes(), $a); - - assertType('int', $b); - assertNativeType('mixed', $b); - assertVariableCertainty(TrinaryLogic::createYes(), $b); - - assertType('int<0, 1>', $c); - assertNativeType('int', $c); - assertVariableCertainty(TrinaryLogic::createMaybe(), $c); - } - - /** @param int $b */ - public function loopThatNeverIterates(int $a, $b): void - { - $j = 0; - for ($i = 0, $j = 10; $i > 10; $i++, $j--) { - $a = rand(0, 1); - $b = rand(0, 1); - $c = rand(0, 1); - } - - assertType('*ERROR*', $i); - assertNativeType('*ERROR*', $i); - assertVariableCertainty(TrinaryLogic::createNo(), $i); - - assertType('0', $j); - assertNativeType('0', $j); - assertVariableCertainty(TrinaryLogic::createYes(), $j); - - assertType('int', $a); - assertNativeType('int', $a); - assertVariableCertainty(TrinaryLogic::createYes(), $a); - - assertType('int', $b); - assertNativeType('mixed', $b); - assertVariableCertainty(TrinaryLogic::createYes(), $b); - - assertType('*ERROR*', $c); - assertNativeType('*ERROR*', $c); - assertVariableCertainty(TrinaryLogic::createNo(), $c); - } - -} diff --git a/tests/PHPStan/Analyser/forLoopNoScopePollution.neon b/tests/PHPStan/Analyser/forLoopNoScopePollution.neon deleted file mode 100644 index 47811f500e..0000000000 --- a/tests/PHPStan/Analyser/forLoopNoScopePollution.neon +++ /dev/null @@ -1,2 +0,0 @@ -parameters: - polluteScopeWithLoopInitialAssignments: false diff --git a/tests/PHPStan/Analyser/nsrt/for-loop.php b/tests/PHPStan/Analyser/nsrt/for-loop.php deleted file mode 100644 index f15cdeb811..0000000000 --- a/tests/PHPStan/Analyser/nsrt/for-loop.php +++ /dev/null @@ -1,107 +0,0 @@ -', $i); - assertNativeType('int<10, max>', $i); - assertVariableCertainty(TrinaryLogic::createYes(), $i); - - assertType('int', $j); - assertNativeType('int', $j); - assertVariableCertainty(TrinaryLogic::createYes(), $j); - - assertType('int<0, 1>', $a); - assertNativeType('int', $a); - assertVariableCertainty(TrinaryLogic::createYes(), $a); - - assertType('int<0, 1>', $b); - assertNativeType('int', $b); - assertVariableCertainty(TrinaryLogic::createYes(), $b); - - assertType('int<0, 1>', $c); - assertNativeType('int', $c); - assertVariableCertainty(TrinaryLogic::createYes(), $c); - } - - /** @param int $b */ - public function loopThatMightIterateAtLeastOnce(int $a, $b): void - { - $j = 0; - for ($i = 0, $j = 10; $i < rand(0, 1); $i++, $j--) { - $a = rand(0, 1); - $b = rand(0, 1); - $c = rand(0, 1); - } - - assertType('int<0, max>', $i); - assertNativeType('int<0, max>', $i); - assertVariableCertainty(TrinaryLogic::createYes(), $i); - - assertType('int', $j); - assertNativeType('int', $j); - assertVariableCertainty(TrinaryLogic::createYes(), $j); - - assertType('int', $a); - assertNativeType('int', $a); - assertVariableCertainty(TrinaryLogic::createYes(), $a); - - assertType('int', $b); - assertNativeType('mixed', $b); - assertVariableCertainty(TrinaryLogic::createYes(), $b); - - assertType('int<0, 1>', $c); - assertNativeType('int', $c); - assertVariableCertainty(TrinaryLogic::createMaybe(), $c); - } - - /** @param int $b */ - public function loopThatNeverIterates(int $a, $b): void - { - $j = 0; - for ($i = 0, $j = 10; $i > 10; $i++, $j--) { - $a = rand(0, 1); - $b = rand(0, 1); - $c = rand(0, 1); - } - - assertType('0', $i); - assertNativeType('0', $i); - assertVariableCertainty(TrinaryLogic::createYes(), $i); - - assertType('10', $j); - assertNativeType('10', $j); - assertVariableCertainty(TrinaryLogic::createYes(), $j); - - assertType('int', $a); - assertNativeType('int', $a); - assertVariableCertainty(TrinaryLogic::createYes(), $a); - - assertType('int', $b); - assertNativeType('mixed', $b); - assertVariableCertainty(TrinaryLogic::createYes(), $b); - - assertType('*ERROR*', $c); - assertNativeType('*ERROR*', $c); - assertVariableCertainty(TrinaryLogic::createNo(), $c); - } - -} diff --git a/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php b/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php index 9a2346eb77..94f0b0ffeb 100644 --- a/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php +++ b/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php @@ -1068,13 +1068,4 @@ public function testBug10228(): void $this->analyse([__DIR__ . '/data/bug-10228.php'], []); } - public function testBug9550(): void - { - $this->cliArgumentsVariablesRegistered = true; - $this->polluteScopeWithLoopInitialAssignments = false; - $this->checkMaybeUndefinedVariables = true; - $this->polluteScopeWithAlwaysIterableForeach = true; - $this->analyse([__DIR__ . '/data/bug-9550.php'], []); - } - } diff --git a/tests/PHPStan/Rules/Variables/data/bug-9550.php b/tests/PHPStan/Rules/Variables/data/bug-9550.php deleted file mode 100644 index ab260ad44c..0000000000 --- a/tests/PHPStan/Rules/Variables/data/bug-9550.php +++ /dev/null @@ -1,32 +0,0 @@ - 0; --$l) { - $vStr = mb_substr($vStrLonger, 0, $l); - if ($vStr !== $vStrLonger) { - $vStrLonger = $vStr; - $vStr = mb_substr($vStr, 0, $l - 3); - $withThreeDots = true; - } else { - $vStrLonger = $vStr; - } - $vStr = str_replace(["\0", "\t", "\n", "\r"], ['\0', '\t', '\n', '\r'], $vStr); - if (mb_strlen($vStr) <= $maxUtf8Length - ($withThreeDots ? 3 : 0)) { - break; - } - } - - return '\'' . $vStr . '\'' . ($withThreeDots ? '...' : ''); - } -}