Skip to content

Commit fc6623f

Browse files
phpstan-botclaude
andcommitted
Fix reference propagation to use chain tracking instead of boolean flag
The boolean propagateReferences=false approach blocks ALL intertwined propagation in recursive calls, breaking nested foreach-by-reference (e.g. bug-13676 where value→row→rows must chain). Replace with intertwinedPropagatedFrom: a list of variable names already visited in the current propagation chain. This prevents circular back-propagation (A→B→A) while allowing legitimate chains (value→row→rows). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e89130e commit fc6623f

1 file changed

Lines changed: 10 additions & 7 deletions

File tree

src/Analyser/MutatingScope.php

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2635,7 +2635,10 @@ public function isUndefinedExpressionAllowed(Expr $expr): bool
26352635
return array_key_exists($exprString, $this->currentlyAllowedUndefinedExpressions);
26362636
}
26372637

2638-
public function assignVariable(string $variableName, Type $type, Type $nativeType, TrinaryLogic $certainty, bool $propagateReferences = true): self
2638+
/**
2639+
* @param list<string> $intertwinedPropagatedFrom
2640+
*/
2641+
public function assignVariable(string $variableName, Type $type, Type $nativeType, TrinaryLogic $certainty, array $intertwinedPropagatedFrom = []): self
26392642
{
26402643
$node = new Variable($variableName);
26412644
$scope = $this->assignExpression($node, $type, $nativeType);
@@ -2647,10 +2650,6 @@ public function assignVariable(string $variableName, Type $type, Type $nativeTyp
26472650
$scope->nativeExpressionTypes[$exprString] = new ExpressionTypeHolder($node, $nativeType, $certainty);
26482651
}
26492652

2650-
if (!$propagateReferences) {
2651-
return $scope;
2652-
}
2653-
26542653
foreach ($scope->expressionTypes as $expressionType) {
26552654
if (!$expressionType->getExpr() instanceof IntertwinedVariableByReferenceWithExpr) {
26562655
continue;
@@ -2668,12 +2667,16 @@ public function assignVariable(string $variableName, Type $type, Type $nativeTyp
26682667
&& is_string($expressionType->getExpr()->getExpr()->name)
26692668
&& !$has->no()
26702669
) {
2670+
$targetVarName = $expressionType->getExpr()->getExpr()->name;
2671+
if (in_array($targetVarName, $intertwinedPropagatedFrom, true)) {
2672+
continue;
2673+
}
26712674
$scope = $scope->assignVariable(
2672-
$expressionType->getExpr()->getExpr()->name,
2675+
$targetVarName,
26732676
$scope->getType($expressionType->getExpr()->getAssignedExpr()),
26742677
$scope->getNativeType($expressionType->getExpr()->getAssignedExpr()),
26752678
$has,
2676-
false,
2679+
array_merge($intertwinedPropagatedFrom, [$variableName]),
26772680
);
26782681
} else {
26792682
$scope = $scope->assignExpression(

0 commit comments

Comments
 (0)