88use PHPStan \Type \Accessory \NonEmptyArrayType ;
99use PHPStan \Type \Accessory \OversizedArrayType ;
1010use PHPStan \Type \ArrayType ;
11+ use PHPStan \Type \CallableType ;
12+ use PHPStan \Type \ClosureType ;
1113use PHPStan \Type \IntersectionType ;
1214use PHPStan \Type \Type ;
1315use PHPStan \Type \TypeCombinator ;
@@ -29,9 +31,12 @@ final class ConstantArrayTypeBuilder
2931{
3032
3133 public const ARRAY_COUNT_LIMIT = 256 ;
34+ private const ARRAY_CLOSURES_COUNT_LIMIT = 16 ;
3235
3336 private bool $ degradeToGeneralArray = false ;
3437
38+ private bool $ degradeClosures = false ;
39+
3540 private bool $ oversized = false ;
3641
3742 /**
@@ -79,6 +84,23 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt
7984 }
8085
8186 if (!$ this ->degradeToGeneralArray ) {
87+ if ($ valueType instanceof ClosureType) {
88+ $ numClosures = 1 ;
89+ foreach ($ this ->valueTypes as $ innerType ) {
90+ if (!($ innerType instanceof ClosureType)) {
91+ continue ;
92+ }
93+
94+ $ numClosures ++;
95+ }
96+
97+ if ($ numClosures >= self ::ARRAY_CLOSURES_COUNT_LIMIT ) {
98+ $ this ->degradeClosures = true ;
99+ $ this ->degradeToGeneralArray = true ;
100+ $ this ->oversized = true ;
101+ }
102+ }
103+
82104 if ($ offsetType === null ) {
83105 $ newAutoIndexes = $ optional ? $ this ->nextAutoIndexes : [];
84106 $ hasOptional = false ;
@@ -291,9 +313,20 @@ public function getArray(): Type
291313 return new ConstantArrayType ($ keyTypes , $ this ->valueTypes , $ this ->nextAutoIndexes , $ this ->optionalKeys , $ this ->isList );
292314 }
293315
316+ $ itemTypes = [];
317+ foreach ($ this ->valueTypes as $ valueType ) {
318+ if ($ this ->degradeClosures && $ valueType instanceof ClosureType) {
319+ continue ;
320+ }
321+ $ itemTypes [] = $ valueType ;
322+ }
323+ if ($ this ->degradeClosures ) {
324+ $ itemTypes [] = new CallableType ();
325+ }
326+
294327 $ array = new ArrayType (
295328 TypeCombinator::union (...$ this ->keyTypes ),
296- TypeCombinator::union (...$ this -> valueTypes ),
329+ TypeCombinator::union (...$ itemTypes ),
297330 );
298331
299332 $ types = [];
0 commit comments