@@ -876,6 +876,90 @@ public function specifyTypesInCondition(
876876 }
877877 }
878878
879+ // infer $arr[$key] after $key = array_search($needle, $arr)
880+ if (
881+ $ expr ->expr instanceof FuncCall
882+ && $ expr ->expr ->name instanceof Name
883+ && $ expr ->expr ->name ->toLowerString () === 'array_search '
884+ && count ($ expr ->expr ->getArgs ()) >= 2
885+ ) {
886+ $ arrayArg = $ expr ->expr ->getArgs ()[1 ]->value ;
887+ $ arrayType = $ scope ->getType ($ arrayArg );
888+
889+ if ($ arrayType ->isArray ()->yes ()) {
890+ if ($ context ->true ()) {
891+ $ dimFetch = new ArrayDimFetch ($ arrayArg , $ expr ->var );
892+
893+ $ specifiedTypes = $ specifiedTypes ->unionWith (
894+ $ this ->create ($ dimFetch , $ arrayType ->getIterableValueType (), TypeSpecifierContext::createTrue (), $ scope ),
895+ );
896+ } elseif ($ expr ->var instanceof Expr \Variable && is_string ($ expr ->var ->name )) {
897+ $ keyType = $ scope ->getType ($ expr ->expr );
898+ $ nonFalseKeyType = TypeCombinator::remove ($ keyType , new ConstantBooleanType (false ));
899+ if (!$ nonFalseKeyType instanceof NeverType && !$ keyType ->isFalse ()->yes ()) {
900+ $ dimFetch = new ArrayDimFetch ($ arrayArg , $ expr ->var );
901+ $ dimFetchString = $ this ->exprPrinter ->printExpr ($ dimFetch );
902+ $ keyExprString = $ this ->exprPrinter ->printExpr ($ expr ->var );
903+
904+ $ holder = new ConditionalExpressionHolder (
905+ [$ keyExprString => ExpressionTypeHolder::createYes ($ expr ->var , $ nonFalseKeyType )],
906+ ExpressionTypeHolder::createYes ($ dimFetch , $ arrayType ->getIterableValueType ()),
907+ );
908+
909+ $ specifiedTypes = $ specifiedTypes ->unionWith (
910+ (new SpecifiedTypes ([], []))->setNewConditionalExpressionHolders ([
911+ $ dimFetchString => [$ holder ->getKey () => $ holder ],
912+ ]),
913+ );
914+ }
915+ }
916+ }
917+ }
918+
919+ // infer $arr[$key] after $key = array_find_key($arr, $callback)
920+ if (
921+ $ expr ->expr instanceof FuncCall
922+ && $ expr ->expr ->name instanceof Name
923+ && $ expr ->expr ->name ->toLowerString () === 'array_find_key '
924+ && count ($ expr ->expr ->getArgs ()) >= 2
925+ ) {
926+ $ arrayArg = $ expr ->expr ->getArgs ()[0 ]->value ;
927+ $ arrayType = $ scope ->getType ($ arrayArg );
928+
929+ if ($ arrayType ->isArray ()->yes ()) {
930+ if ($ context ->true ()) {
931+ $ specifiedTypes = $ specifiedTypes ->unionWith (
932+ $ this ->create ($ arrayArg , new NonEmptyArrayType (), TypeSpecifierContext::createTrue (), $ scope ),
933+ );
934+
935+ $ dimFetch = new ArrayDimFetch ($ arrayArg , $ expr ->var );
936+
937+ $ specifiedTypes = $ specifiedTypes ->unionWith (
938+ $ this ->create ($ dimFetch , $ arrayType ->getIterableValueType (), TypeSpecifierContext::createTrue (), $ scope ),
939+ );
940+ } elseif ($ expr ->var instanceof Expr \Variable && is_string ($ expr ->var ->name )) {
941+ $ keyType = $ scope ->getType ($ expr ->expr );
942+ $ nonNullKeyType = TypeCombinator::removeNull ($ keyType );
943+ if (!$ nonNullKeyType instanceof NeverType && !$ keyType ->isNull ()->yes ()) {
944+ $ dimFetch = new ArrayDimFetch ($ arrayArg , $ expr ->var );
945+ $ dimFetchString = $ this ->exprPrinter ->printExpr ($ dimFetch );
946+ $ keyExprString = $ this ->exprPrinter ->printExpr ($ expr ->var );
947+
948+ $ holder = new ConditionalExpressionHolder (
949+ [$ keyExprString => ExpressionTypeHolder::createYes ($ expr ->var , $ nonNullKeyType )],
950+ ExpressionTypeHolder::createYes ($ dimFetch , $ arrayType ->getIterableValueType ()),
951+ );
952+
953+ $ specifiedTypes = $ specifiedTypes ->unionWith (
954+ (new SpecifiedTypes ([], []))->setNewConditionalExpressionHolders ([
955+ $ dimFetchString => [$ holder ->getKey () => $ holder ],
956+ ]),
957+ );
958+ }
959+ }
960+ }
961+ }
962+
879963 if ($ context ->null ()) {
880964 // infer $arr[$key] after $key = array_rand($arr)
881965 if (
@@ -933,27 +1017,6 @@ public function specifyTypesInCondition(
9331017 return $ specifiedTypes ;
9341018 }
9351019
936- if ($ context ->true ()) {
937- // infer $arr[$key] after $key = array_search($needle, $arr)
938- if (
939- $ expr ->expr instanceof FuncCall
940- && $ expr ->expr ->name instanceof Name
941- && $ expr ->expr ->name ->toLowerString () === 'array_search '
942- && count ($ expr ->expr ->getArgs ()) >= 2
943- ) {
944- $ arrayArg = $ expr ->expr ->getArgs ()[1 ]->value ;
945- $ arrayType = $ scope ->getType ($ arrayArg );
946-
947- if ($ arrayType ->isArray ()->yes ()) {
948- $ dimFetch = new ArrayDimFetch ($ arrayArg , $ expr ->var );
949- $ iterableValueType = $ arrayType ->getIterableValueType ();
950-
951- return $ specifiedTypes ->unionWith (
952- $ this ->create ($ dimFetch , $ iterableValueType , TypeSpecifierContext::createTrue (), $ scope ),
953- );
954- }
955- }
956- }
9571020 return $ specifiedTypes ;
9581021 } elseif (
9591022 $ expr instanceof Expr \Isset_
@@ -3016,10 +3079,11 @@ private function resolveNormalizedIdentical(Expr\BinaryOp\Identical $expr, Scope
30163079
30173080 // array_key_first($a) !== null
30183081 // array_key_last($a) !== null
3082+ // array_find_key($a, $cb) !== null
30193083 if (
30203084 $ unwrappedLeftExpr instanceof FuncCall
30213085 && $ unwrappedLeftExpr ->name instanceof Name
3022- && in_array ($ unwrappedLeftExpr ->name ->toLowerString (), ['array_key_first ' , 'array_key_last ' ], true )
3086+ && in_array ($ unwrappedLeftExpr ->name ->toLowerString (), ['array_key_first ' , 'array_key_last ' , ' array_find_key ' ], true )
30233087 && isset ($ unwrappedLeftExpr ->getArgs ()[0 ])
30243088 && $ rightType ->isNull ()->yes ()
30253089 ) {
0 commit comments