|
38 | 38 | use PHPStan\Type\Accessory\AccessoryNonEmptyStringType; |
39 | 39 | use PHPStan\Type\Accessory\AccessoryNonFalsyStringType; |
40 | 40 | use PHPStan\Type\Accessory\HasOffsetType; |
| 41 | +use PHPStan\Type\Accessory\HasOffsetValueType; |
41 | 42 | use PHPStan\Type\Accessory\HasPropertyType; |
42 | 43 | use PHPStan\Type\Accessory\NonEmptyArrayType; |
43 | 44 | use PHPStan\Type\ArrayType; |
|
91 | 92 | #[AutowiredService(name: 'typeSpecifier', factory: '@typeSpecifierFactory::create', as: TypeSpecifier::class)] |
92 | 93 | final class LegacyTypeSpecifier implements TypeSpecifier |
93 | 94 | { |
| 95 | + private const MAX_ACCESSORIES_LIMIT = 8; |
94 | 96 |
|
95 | 97 | /** @var MethodTypeSpecifyingExtension[][]|null */ |
96 | 98 | private ?array $methodTypeSpecifyingExtensionsByClass = null; |
@@ -1189,7 +1191,27 @@ private function specifyTypesForCountFuncCall( |
1189 | 1191 | $builderData[] = [$offsetType, $arrayType->getOffsetValueType($offsetType), !$hasOffset->yes()]; |
1190 | 1192 | } |
1191 | 1193 | } else { |
1192 | | - $resultTypes[] = TypeCombinator::intersect($arrayType, new NonEmptyArrayType()); |
| 1194 | + $intersection = []; |
| 1195 | + $intersection[] = $arrayType; |
| 1196 | + $intersection[] = new NonEmptyArrayType(); |
| 1197 | + |
| 1198 | + $zero = new ConstantIntegerType(0); |
| 1199 | + $i = 0; |
| 1200 | + foreach ($builderData as [$offsetType, $valueType]) { |
| 1201 | + // non-empty-list already implies the offset 0 |
| 1202 | + if ($zero->isSuperTypeOf($offsetType)->yes()) { |
| 1203 | + continue; |
| 1204 | + } |
| 1205 | + |
| 1206 | + if ($i > self::MAX_ACCESSORIES_LIMIT) { |
| 1207 | + break; |
| 1208 | + } |
| 1209 | + |
| 1210 | + $intersection[] = new HasOffsetValueType($offsetType, $valueType); |
| 1211 | + $i++; |
| 1212 | + } |
| 1213 | + |
| 1214 | + $resultTypes[] = TypeCombinator::intersect(...$intersection); |
1193 | 1215 | continue; |
1194 | 1216 | } |
1195 | 1217 |
|
|
0 commit comments