diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 59e7d30a0dd..9a90cb0cd19 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -4647,7 +4647,55 @@ public function equals(self $otherScope): bool if (!$this->compareVariableTypeHolders($this->expressionTypes, $otherScope->expressionTypes)) { return false; } - return $this->compareVariableTypeHolders($this->nativeExpressionTypes, $otherScope->nativeExpressionTypes); + if (!$this->compareVariableTypeHolders($this->nativeExpressionTypes, $otherScope->nativeExpressionTypes)) { + return false; + } + + return $this->compareConditionalExpressions($this->conditionalExpressions, $otherScope->conditionalExpressions); + } + + /** + * @param array $conditionalExpressions + * @param array $otherConditionalExpressions + */ + private function compareConditionalExpressions(array $conditionalExpressions, array $otherConditionalExpressions): bool + { + if (count($conditionalExpressions) !== count($otherConditionalExpressions)) { + return false; + } + foreach ($conditionalExpressions as $exprString => $holders) { + if (!isset($otherConditionalExpressions[$exprString])) { + return false; + } + $otherHolders = $otherConditionalExpressions[$exprString]; + if (count($holders) !== count($otherHolders)) { + return false; + } + foreach ($holders as $key => $holder) { + if (!isset($otherHolders[$key])) { + return false; + } + $otherHolder = $otherHolders[$key]; + if (!$holder->getTypeHolder()->equals($otherHolder->getTypeHolder())) { + return false; + } + $conditions = $holder->getConditionExpressionTypeHolders(); + $otherConditions = $otherHolder->getConditionExpressionTypeHolders(); + if (count($conditions) !== count($otherConditions)) { + return false; + } + foreach ($conditions as $conditionExprString => $conditionHolder) { + if (!isset($otherConditions[$conditionExprString])) { + return false; + } + if (!$conditionHolder->equals($otherConditions[$conditionExprString])) { + return false; + } + } + } + } + + return true; } /** diff --git a/tests/PHPStan/Analyser/nsrt/loop-fixpoint-conditional-expressions.php b/tests/PHPStan/Analyser/nsrt/loop-fixpoint-conditional-expressions.php new file mode 100644 index 00000000000..4fbeb2b3d6b --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/loop-fixpoint-conditional-expressions.php @@ -0,0 +1,33 @@ + $items */ + public function run(array $items): void + { + foreach ([1, 2] as $_) { + $toCurrent = 0; + if ($items !== []) { + $toCurrent = count($items); + } + + while ($toCurrent > 0) { + assertType('list', $items); + $item = array_shift($items); + assertType('LoopFixpointConditionalExpressions\Item|null', $item); + $toCurrent--; + } + } + } + +}