diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 88a11de133..f5cbf37d35 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -3432,11 +3432,29 @@ private function intersectConditionalExpressions(array $otherConditionalExpressi $otherHolders = $otherConditionalExpressions[$exprString]; $intersectedHolders = []; - foreach ($holders as $key => $holder) { - if (!array_key_exists($key, $otherHolders)) { + foreach ($holders as $holder) { + $key = $holder->getKey(); + if (array_key_exists($key, $otherHolders)) { + $intersectedHolders[$key] = $holder; continue; } - $intersectedHolders[$key] = $holder; + + foreach ($otherHolders as $otherHolder) { + if (!$this->conditionExpressionTypeHoldersEqual( + $holder->getConditionExpressionTypeHolders(), + $otherHolder->getConditionExpressionTypeHolders(), + )) { + continue; + } + + $mergedTypeHolder = $holder->getTypeHolder()->and($otherHolder->getTypeHolder()); + $mergedHolder = new ConditionalExpressionHolder( + $holder->getConditionExpressionTypeHolders(), + $mergedTypeHolder, + ); + $intersectedHolders[$mergedHolder->getKey()] = $mergedHolder; + break; + } } if (count($intersectedHolders) === 0) { @@ -3449,6 +3467,28 @@ private function intersectConditionalExpressions(array $otherConditionalExpressi return $newConditionalExpressions; } + /** + * @param array $a + * @param array $b + */ + private function conditionExpressionTypeHoldersEqual(array $a, array $b): bool + { + if (count($a) !== count($b)) { + return false; + } + + foreach ($a as $exprString => $holder) { + if (!array_key_exists($exprString, $b)) { + return false; + } + if (!$holder->equals($b[$exprString])) { + return false; + } + } + + return true; + } + /** * @param array $newConditionalExpressions * @param array $existingConditionalExpressions diff --git a/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php b/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php index 2dde59f142..0d43017614 100644 --- a/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php +++ b/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php @@ -1393,6 +1393,16 @@ public function testBug6830(): void $this->analyse([__DIR__ . '/data/bug-6830.php'], []); } + public function testBug6830b(): void + { + $this->cliArgumentsVariablesRegistered = true; + $this->polluteScopeWithLoopInitialAssignments = false; + $this->checkMaybeUndefinedVariables = true; + $this->polluteScopeWithAlwaysIterableForeach = true; + + $this->analyse([__DIR__ . '/data/bug-6830b.php'], []); + } + public function testBug14019(): void { $this->cliArgumentsVariablesRegistered = true; diff --git a/tests/PHPStan/Rules/Variables/data/bug-6830b.php b/tests/PHPStan/Rules/Variables/data/bug-6830b.php new file mode 100644 index 0000000000..39d5e9d375 --- /dev/null +++ b/tests/PHPStan/Rules/Variables/data/bug-6830b.php @@ -0,0 +1,20 @@ +