Skip to content

Commit

Permalink
Do not generalize big array when combined with empty array
Browse files Browse the repository at this point in the history
  • Loading branch information
RobertMe authored and ondrejmirtes committed Apr 6, 2024
1 parent e74cd7c commit c1aeb64
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 2 deletions.
12 changes: 10 additions & 2 deletions src/Type/TypeCombinator.php
Original file line number Diff line number Diff line change
Expand Up @@ -664,12 +664,19 @@ private static function processArrayTypes(array $arrayTypes): array
$valueTypesForGeneralArray = [];
$generalArrayOccurred = false;
$constantKeyTypesNumbered = [];
$filledArrays = 0;
$overflowed = false;

/** @var int|float $nextConstantKeyTypeIndex */
$nextConstantKeyTypeIndex = 1;

foreach ($arrayTypes as $arrayType) {
if ($generalArrayOccurred || !$arrayType->isConstantArray()->yes()) {
$isConstantArray = $arrayType->isConstantArray()->yes();
if (!$isConstantArray || !$arrayType->isIterableAtLeastOnce()->no()) {
$filledArrays++;
}

if ($generalArrayOccurred || !$isConstantArray) {
foreach ($arrayType->getArrays() as $type) {
$keyTypesForGeneralArray[] = $type->getIterableKeyType();
$valueTypesForGeneralArray[] = $type->getItemType();
Expand All @@ -693,13 +700,14 @@ private static function processArrayTypes(array $arrayTypes): array
$nextConstantKeyTypeIndex *= 2;
if (!is_int($nextConstantKeyTypeIndex)) {
$generalArrayOccurred = true;
$overflowed = true;
continue 2;
}
}
}
}

if ($generalArrayOccurred) {
if ($generalArrayOccurred && (!$overflowed || $filledArrays > 1)) {
$scopes = [];
$useTemplateArray = true;
foreach ($arrayTypes as $arrayType) {
Expand Down
1 change: 1 addition & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1461,6 +1461,7 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10468.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6613.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10187.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10834.php');
}

/**
Expand Down
21 changes: 21 additions & 0 deletions tests/PHPStan/Analyser/data/bug-10834.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

use function PHPStan\Testing\assertType;

/**
* @return array{1: string, 2: int, 3: bool, 4: string, 5: int, 6: bool, 7: string, 8: int, 9: bool, 10: string, 11: int, 12: bool, 13: string, 14: int, 15: bool, 16: string, 17: int, 18: bool, 19: string, 20: int, 21: bool, 22: string, 23: int, 24: bool, 25: string, 26: int, 27: bool, 28: string, 29: int, 30: bool, 31: string, 32: int, 33: bool, 34: string, 35: int, 36: bool, 37: string, 38: int, 39: bool, 40: string, 41: int, 42: bool, 43: string, 44: int, 45: bool, 46: string, 47: int, 48: bool, 49: string, 50: int, 51: bool, 52: string, 53: int, 54: bool, 55: string, 56: int, 57: bool, 58: string, 59: int, 60: bool, 61: string, 62: int, 63: bool, 64: float}|null
*/
function returnArrayOrNull()
{
return null;
}

function test(): void {
$arrayOrNull = returnArrayOrNull();

assertType('array{1: string, 2: int, 3: bool, 4: string, 5: int, 6: bool, 7: string, 8: int, 9: bool, 10: string, 11: int, 12: bool, 13: string, 14: int, 15: bool, 16: string, 17: int, 18: bool, 19: string, 20: int, 21: bool, 22: string, 23: int, 24: bool, 25: string, 26: int, 27: bool, 28: string, 29: int, 30: bool, 31: string, 32: int, 33: bool, 34: string, 35: int, 36: bool, 37: string, 38: int, 39: bool, 40: string, 41: int, 42: bool, 43: string, 44: int, 45: bool, 46: string, 47: int, 48: bool, 49: string, 50: int, 51: bool, 52: string, 53: int, 54: bool, 55: string, 56: int, 57: bool, 58: string, 59: int, 60: bool, 61: string, 62: int, 63: bool, 64: float}|null', $arrayOrNull);
assertType('array{}|array{1: string, 2: int, 3: bool, 4: string, 5: int, 6: bool, 7: string, 8: int, 9: bool, 10: string, 11: int, 12: bool, 13: string, 14: int, 15: bool, 16: string, 17: int, 18: bool, 19: string, 20: int, 21: bool, 22: string, 23: int, 24: bool, 25: string, 26: int, 27: bool, 28: string, 29: int, 30: bool, 31: string, 32: int, 33: bool, 34: string, 35: int, 36: bool, 37: string, 38: int, 39: bool, 40: string, 41: int, 42: bool, 43: string, 44: int, 45: bool, 46: string, 47: int, 48: bool, 49: string, 50: int, 51: bool, 52: string, 53: int, 54: bool, 55: string, 56: int, 57: bool, 58: string, 59: int, 60: bool, 61: string, 62: int, 63: bool, 64: float}', $arrayOrNull ?? []);
assertType('array{}|array{1: string, 2: int, 3: bool, 4: string, 5: int, 6: bool, 7: string, 8: int, 9: bool, 10: string, 11: int, 12: bool, 13: string, 14: int, 15: bool, 16: string, 17: int, 18: bool, 19: string, 20: int, 21: bool, 22: string, 23: int, 24: bool, 25: string, 26: int, 27: bool, 28: string, 29: int, 30: bool, 31: string, 32: int, 33: bool, 34: string, 35: int, 36: bool, 37: string, 38: int, 39: bool, 40: string, 41: int, 42: bool, 43: string, 44: int, 45: bool, 46: string, 47: int, 48: bool, 49: string, 50: int, 51: bool, 52: string, 53: int, 54: bool, 55: string, 56: int, 57: bool, 58: string, 59: int, 60: bool, 61: string, 62: int, 63: bool, 64: float}|null', rand() ? $arrayOrNull : []);
}

0 comments on commit c1aeb64

Please sign in to comment.