|
4 | 4 |
|
5 | 5 | use Nette\Utils\Strings; |
6 | 6 | use PHPStan\Analyser\OutOfClassScope; |
7 | | -use PHPStan\Internal\CombinationsHelper; |
8 | 7 | use PHPStan\Php\PhpVersion; |
9 | 8 | use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode; |
10 | 9 | use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode; |
@@ -1997,38 +1996,43 @@ public static function isValidIdentifier(string $value): bool |
1997 | 1996 |
|
1998 | 1997 | public function getFiniteTypes(): array |
1999 | 1998 | { |
2000 | | - $arraysArraysForCombinations = []; |
2001 | | - $count = 0; |
2002 | | - foreach ($this->getAllArrays() as $array) { |
2003 | | - $values = $array->getValueTypes(); |
2004 | | - $arraysForCombinations = []; |
2005 | | - $combinationCount = 1; |
2006 | | - foreach ($values as $valueType) { |
2007 | | - $finiteTypes = $valueType->getFiniteTypes(); |
2008 | | - if ($finiteTypes === []) { |
2009 | | - return []; |
| 1999 | + $limit = InitializerExprTypeResolver::CALCULATE_SCALARS_LIMIT; |
| 2000 | + |
| 2001 | + // Build finite array types incrementally, processing one key at a time. |
| 2002 | + // For optional keys, fork each partial result into with/without variants. |
| 2003 | + // This avoids generating 2^N ConstantArrayType objects via getAllArrays(). |
| 2004 | + /** @var list<ConstantArrayTypeBuilder> $partials */ |
| 2005 | + $partials = [ConstantArrayTypeBuilder::createEmpty()]; |
| 2006 | + |
| 2007 | + foreach ($this->keyTypes as $i => $keyType) { |
| 2008 | + $finiteValueTypes = $this->valueTypes[$i]->getFiniteTypes(); |
| 2009 | + if ($finiteValueTypes === []) { |
| 2010 | + return []; |
| 2011 | + } |
| 2012 | + |
| 2013 | + $isOptional = $this->isOptionalKey($i); |
| 2014 | + $newPartials = []; |
| 2015 | + |
| 2016 | + foreach ($partials as $partial) { |
| 2017 | + if ($isOptional) { |
| 2018 | + $newPartials[] = clone $partial; |
| 2019 | + } |
| 2020 | + foreach ($finiteValueTypes as $finiteValueType) { |
| 2021 | + $newPartial = clone $partial; |
| 2022 | + $newPartial->setOffsetValueType($keyType, $finiteValueType); |
| 2023 | + $newPartials[] = $newPartial; |
2010 | 2024 | } |
2011 | | - $arraysForCombinations[] = $finiteTypes; |
2012 | | - $combinationCount *= count($finiteTypes); |
2013 | 2025 | } |
2014 | | - $arraysArraysForCombinations[] = $arraysForCombinations; |
2015 | | - $count += $combinationCount; |
2016 | | - } |
2017 | 2026 |
|
2018 | | - if ($count > InitializerExprTypeResolver::CALCULATE_SCALARS_LIMIT) { |
2019 | | - return []; |
| 2027 | + $partials = $newPartials; |
| 2028 | + if (count($partials) > $limit) { |
| 2029 | + return []; |
| 2030 | + } |
2020 | 2031 | } |
2021 | 2032 |
|
2022 | 2033 | $finiteTypes = []; |
2023 | | - foreach ($arraysArraysForCombinations as $arraysForCombinations) { |
2024 | | - $combinations = CombinationsHelper::combinations($arraysForCombinations); |
2025 | | - foreach ($combinations as $combination) { |
2026 | | - $builder = ConstantArrayTypeBuilder::createEmpty(); |
2027 | | - foreach ($combination as $i => $v) { |
2028 | | - $builder->setOffsetValueType($this->keyTypes[$i], $v); |
2029 | | - } |
2030 | | - $finiteTypes[] = $builder->getArray(); |
2031 | | - } |
| 2034 | + foreach ($partials as $partial) { |
| 2035 | + $finiteTypes[] = $partial->getArray(); |
2032 | 2036 | } |
2033 | 2037 |
|
2034 | 2038 | return $finiteTypes; |
|
0 commit comments