Skip to content

Commit 40bab7a

Browse files
phpstan-botclaude
andcommitted
Skip implicit-key by-ref tracking when index is uncertain due to non-constant keys
When a non-constant key appears in an array literal, the implicit index counter becomes unreliable. Stop setting up intertwined refs for implicit-keyed by-ref items after that point, since we can't know their actual indices. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 85e52c5 commit 40bab7a

2 files changed

Lines changed: 24 additions & 1 deletion

File tree

src/Analyser/ExprHandler/AssignHandler.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ public function processAssignVar(
319319

320320
if ($assignedExpr instanceof Expr\Array_) {
321321
$implicitIndex = 0;
322+
$implicitIndexCertain = true;
322323
foreach ($assignedExpr->items as $arrayItem) {
323324
if ($arrayItem->key !== null) {
324325
$keyType = $scope->getType($arrayItem->key);
@@ -329,7 +330,11 @@ public function processAssignVar(
329330
if (is_int($keyValue) && $keyValue >= $implicitIndex) {
330331
$implicitIndex = $keyValue + 1;
331332
}
333+
} else {
334+
$implicitIndexCertain = false;
332335
}
336+
} else {
337+
$implicitIndexCertain = false;
333338
}
334339
}
335340

@@ -343,9 +348,12 @@ public function processAssignVar(
343348
$refVarName = $arrayItem->value->name;
344349
if ($arrayItem->key !== null) {
345350
$dimExpr = $arrayItem->key;
346-
} else {
351+
} elseif ($implicitIndexCertain) {
347352
$dimExpr = new Node\Scalar\Int_($implicitIndex);
348353
$implicitIndex++;
354+
} else {
355+
$implicitIndex++;
356+
continue;
349357
}
350358

351359
$dimFetchExpr = new ArrayDimFetch(new Variable($var->name), $dimExpr);

tests/PHPStan/Analyser/nsrt/bug-14333.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,21 @@ function testMultipleByRefInArray(): void
3333
assertType("'bar'", $c);
3434
}
3535

36+
function testNonConstantKeyBreaksImplicitIndex(int $key): void
37+
{
38+
$a = 1;
39+
$c = 'test';
40+
41+
$b = [$key => 'x', &$a, &$c];
42+
assertType('1', $a);
43+
assertType("'test'", $c);
44+
45+
// Since $key is non-constant, we don't know the implicit indices of &$a and &$c
46+
// so we can't track the reference propagation
47+
$b[0] = 2;
48+
assertType('1', $a);
49+
}
50+
3651
function testNested(): void
3752
{
3853
$a = 1;

0 commit comments

Comments
 (0)