1616use PHPStan \Reflection \FunctionReflection ;
1717use PHPStan \Type \Accessory \NonEmptyArrayType ;
1818use PHPStan \Type \ArrayType ;
19+ use PHPStan \Type \Constant \ConstantArrayType ;
1920use PHPStan \Type \FunctionTypeSpecifyingExtension ;
2021use PHPStan \Type \MixedType ;
21- use PHPStan \Type \NeverType ;
2222use PHPStan \Type \Type ;
2323use PHPStan \Type \TypeCombinator ;
2424use function count ;
@@ -167,10 +167,9 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
167167 }
168168
169169 /**
170- * Computes the type to narrow the needle against, or null if no narrowing
171- * should occur. In true context, returns the array value type directly.
172- * In false context, returns only the values guaranteed to be in every
173- * possible variant of the array.
170+ * Computes the type to narrow the needle against, or null if no narrowing should occur.
171+ * In true context, returns the array value type directly.
172+ * In false context, returns only the values guaranteed to be in every possible variant of the array.
174173 */
175174 private function computeNeedleNarrowingType (TypeSpecifierContext $ context , Type $ needleType , Type $ arrayType , Type $ arrayValueType ): ?Type
176175 {
@@ -187,35 +186,43 @@ private function computeNeedleNarrowingType(TypeSpecifierContext $context, Type
187186 }
188187
189188 $ arrays = $ arrayType ->getArrays ();
190- $ innerValueTypes = [];
189+ $ guaranteedValueTypePerArray = [];
191190 foreach ($ arrays as $ array ) {
192- $ constantArrays = $ array ->getConstantArrays ();
193- if (count ($ constantArrays ) > 0 ) {
194- foreach ($ constantArrays as $ constantArray ) {
195- $ guaranteedTypes = [];
196- foreach ($ constantArray ->getValueTypes () as $ i => $ valueType ) {
197- if (!$ constantArray ->isOptionalKey ($ i )) {
198- $ guaranteedTypes [] = $ valueType ;
199- }
191+ if ($ array instanceof ConstantArrayType) {
192+ $ innerGuaranteeValueType = [];
193+ foreach ($ array ->getValueTypes () as $ i => $ valueType ) {
194+ if ($ array ->isOptionalKey ($ i )) {
195+ continue ;
200196 }
201- $ innerValueTypes [] = count ($ guaranteedTypes ) > 0
202- ? TypeCombinator::union (...$ guaranteedTypes )
203- : new NeverType ();
197+
198+ $ finiteTypes = $ valueType ->getFiniteTypes ();
199+ if (count ($ finiteTypes ) !== 1 ) {
200+ continue ;
201+ }
202+
203+ $ innerGuaranteeValueType [] = $ finiteTypes [0 ];
204+ }
205+
206+ if (count ($ innerGuaranteeValueType ) === 0 ) {
207+ return null ;
204208 }
209+
210+ $ guaranteedValueTypePerArray [] = TypeCombinator::union (...$ innerGuaranteeValueType );
205211 } else {
206- $ valueType = $ array ->getIterableValueType ();
207- if (count ($ valueType -> getFiniteTypes ()) = == 1 ) {
208- $ innerValueTypes [] = $ valueType ;
212+ $ finiteValueType = $ array ->getIterableValueType ()-> getFiniteTypes ();
213+ if (count ($ finiteValueType ) ! == 1 ) {
214+ return null ;
209215 }
216+
217+ $ guaranteedValueTypePerArray [] = $ finiteValueType [0 ];
210218 }
211219 }
212220
213- if (count ($ innerValueTypes ) === 0 ) {
221+ if (count ($ guaranteedValueTypePerArray ) === 0 ) {
214222 return null ;
215223 }
216224
217- $ guaranteedValueType = TypeCombinator::intersect (...$ innerValueTypes );
218-
225+ $ guaranteedValueType = TypeCombinator::intersect (...$ guaranteedValueTypePerArray );
219226 if (count ($ guaranteedValueType ->getFiniteTypes ()) === 0 ) {
220227 return null ;
221228 }
0 commit comments