Skip to content

Commit 0888c0d

Browse files
committed
Revert "Unroll foreach over small constant arrays to make keys non-optional"
This reverts commit 62e722d.
1 parent 62e722d commit 0888c0d

2 files changed

Lines changed: 1 addition & 102 deletions

File tree

src/Analyser/NodeScopeResolver.php

Lines changed: 0 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,6 @@ class NodeScopeResolver
187187

188188
private const LOOP_SCOPE_ITERATIONS = 3;
189189
private const GENERALIZE_AFTER_ITERATION = 1;
190-
private const FOREACH_UNROLL_LIMIT = 8;
191190

192191
/** @var array<string, true> filePath(string) => bool(true) */
193192
private array $analysedFiles = [];
@@ -1384,106 +1383,6 @@ public function processStmtNode(
13841383
// get types from finalScope, but don't create new variables
13851384
}
13861385

1387-
if (
1388-
$context->isTopLevel()
1389-
&& $isIterableAtLeastOnce->yes()
1390-
&& count($breakExitPoints) === 0
1391-
&& !$stmt->byRef
1392-
&& $exprType->isConstantArray()->yes()
1393-
&& $stmt->valueVar instanceof Variable && is_string($stmt->valueVar->name)
1394-
&& ($stmt->keyVar === null || ($stmt->keyVar instanceof Variable && is_string($stmt->keyVar->name)))
1395-
) {
1396-
$constantArraysForUnroll = $exprType->getConstantArrays();
1397-
if (
1398-
count($constantArraysForUnroll) === 1
1399-
&& count($constantArraysForUnroll[0]->getOptionalKeys()) === 0
1400-
&& ($unrollKeyCount = count($constantArraysForUnroll[0]->getKeyTypes())) > 0
1401-
&& $unrollKeyCount <= self::FOREACH_UNROLL_LIMIT
1402-
) {
1403-
$unrolledScope = $scope;
1404-
$unrollSucceeded = true;
1405-
foreach ($constantArraysForUnroll[0]->getKeyTypes() as $i => $keyType) {
1406-
$valueType = $constantArraysForUnroll[0]->getValueTypes()[$i];
1407-
1408-
$iterScope = $unrolledScope->assignVariable(
1409-
$stmt->valueVar->name,
1410-
$valueType,
1411-
$valueType,
1412-
TrinaryLogic::createYes(),
1413-
);
1414-
if ($stmt->keyVar instanceof Variable && is_string($stmt->keyVar->name)) {
1415-
$iterScope = $iterScope->assignVariable(
1416-
$stmt->keyVar->name,
1417-
$keyType,
1418-
$keyType,
1419-
TrinaryLogic::createYes(),
1420-
);
1421-
}
1422-
1423-
$iterStorage = $storage->duplicate();
1424-
$iterResult = $this->processStmtNodesInternal(
1425-
$stmt, $stmt->stmts, $iterScope, $iterStorage,
1426-
new NoopNodeCallback(), $context->enterDeep(),
1427-
)->filterOutLoopExitPoints();
1428-
1429-
$unrolledScope = $iterResult->getScope();
1430-
foreach ($iterResult->getExitPointsByType(Continue_::class) as $continueExitPoint) {
1431-
$unrolledScope = $unrolledScope->mergeWith($continueExitPoint->getScope());
1432-
}
1433-
1434-
if (
1435-
count($iterResult->getExitPointsByType(Break_::class)) > 0
1436-
|| $iterResult->isAlwaysTerminating()
1437-
) {
1438-
$unrollSucceeded = false;
1439-
break;
1440-
}
1441-
}
1442-
1443-
if ($unrollSucceeded) {
1444-
foreach ($unrolledScope->expressionTypes as $exprString => $holder) {
1445-
if (!str_starts_with($exprString, '$') || str_contains($exprString, '[') || str_contains($exprString, '>')) {
1446-
continue;
1447-
}
1448-
if (!$holder->getCertainty()->yes()) {
1449-
continue;
1450-
}
1451-
$unrolledType = $holder->getType();
1452-
if (!$unrolledType->isConstantArray()->yes()) {
1453-
continue;
1454-
}
1455-
if (!isset($finalScope->expressionTypes[$exprString])) {
1456-
continue;
1457-
}
1458-
$finalHolder = $finalScope->expressionTypes[$exprString];
1459-
$finalType = $finalHolder->getType();
1460-
if (!$finalType->isConstantArray()->yes()) {
1461-
continue;
1462-
}
1463-
1464-
$unrolledArrays = $unrolledType->getConstantArrays();
1465-
$finalArrays = $finalType->getConstantArrays();
1466-
if (
1467-
count($unrolledArrays) === 1
1468-
&& count($finalArrays) === 1
1469-
&& count($unrolledArrays[0]->getOptionalKeys()) < count($finalArrays[0]->getOptionalKeys())
1470-
&& count($unrolledArrays[0]->getKeyTypes()) === count($finalArrays[0]->getKeyTypes())
1471-
) {
1472-
$varName = substr($exprString, 1);
1473-
$varExpr = $holder->getExpr();
1474-
$nativeType = $unrolledScope->getNativeType($varExpr);
1475-
$finalScope = $finalScope->assignVariable(
1476-
$varName,
1477-
$unrolledType,
1478-
$nativeType,
1479-
TrinaryLogic::createYes(),
1480-
);
1481-
}
1482-
}
1483-
}
1484-
}
1485-
}
1486-
14871386
if (!$isIterableAtLeastOnce->no()) {
14881387
$throwPoints = array_merge($throwPoints, $finalScopeResult->getThrowPoints());
14891388
$impurePoints = array_merge($impurePoints, $finalScopeResult->getImpurePoints());

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public function break(string $s, int $i): array
1313
foreach (['b', 'c'] as $letter) {
1414
$array[$letter] = $i;
1515
}
16-
assertType('array{a: string, b: int, c: int}', $array);
16+
assertType('array{a: string, b?: int, c?: int}', $array);
1717
return $array;
1818
}
1919
}

0 commit comments

Comments
 (0)