Skip to content

Commit 61c54ae

Browse files
phpstan-botclaude
authored 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 5b16da0 commit 61c54ae

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
@@ -2565,7 +2565,10 @@ public function isUndefinedExpressionAllowed(Expr $expr): bool
25652565
return array_key_exists($exprString, $this->currentlyAllowedUndefinedExpressions);
25662566
}
25672567

2568-
public function assignVariable(string $variableName, Type $type, Type $nativeType, TrinaryLogic $certainty, bool $propagateReferences = true): self
2568+
/**
2569+
* @param list<string> $intertwinedPropagatedFrom
2570+
*/
2571+
public function assignVariable(string $variableName, Type $type, Type $nativeType, TrinaryLogic $certainty, array $intertwinedPropagatedFrom = []): self
25692572
{
25702573
$node = new Variable($variableName);
25712574
$scope = $this->assignExpression($node, $type, $nativeType);
@@ -2577,10 +2580,6 @@ public function assignVariable(string $variableName, Type $type, Type $nativeTyp
25772580
$scope->nativeExpressionTypes[$exprString] = new ExpressionTypeHolder($node, $nativeType, $certainty);
25782581
}
25792582

2580-
if (!$propagateReferences) {
2581-
return $scope;
2582-
}
2583-
25842583
foreach ($scope->expressionTypes as $expressionType) {
25852584
if (!$expressionType->getExpr() instanceof IntertwinedVariableByReferenceWithExpr) {
25862585
continue;
@@ -2598,12 +2597,16 @@ public function assignVariable(string $variableName, Type $type, Type $nativeTyp
25982597
&& is_string($expressionType->getExpr()->getExpr()->name)
25992598
&& !$has->no()
26002599
) {
2600+
$targetVarName = $expressionType->getExpr()->getExpr()->name;
2601+
if (in_array($targetVarName, $intertwinedPropagatedFrom, true)) {
2602+
continue;
2603+
}
26012604
$scope = $scope->assignVariable(
2602-
$expressionType->getExpr()->getExpr()->name,
2605+
$targetVarName,
26032606
$scope->getType($expressionType->getExpr()->getAssignedExpr()),
26042607
$scope->getNativeType($expressionType->getExpr()->getAssignedExpr()),
26052608
$has,
2606-
false,
2609+
array_merge($intertwinedPropagatedFrom, [$variableName]),
26072610
);
26082611
} else {
26092612
$scope = $scope->assignExpression(

0 commit comments

Comments
 (0)