@@ -734,15 +734,7 @@ public function specifyTypesInCondition(
734734 $ leftTypes = $ this ->specifyTypesInCondition ($ scope , $ expr ->left , $ context )->setRootExpr ($ expr );
735735 $ rightScope = $ scope ->filterByTruthyValue ($ expr ->left );
736736 $ rightTypes = $ this ->specifyTypesInCondition ($ rightScope , $ expr ->right , $ context )->setRootExpr ($ expr );
737- if ($ context ->true ()) {
738- $ types = $ leftTypes ->unionWith ($ rightTypes );
739- } else {
740- $ normalizedLeft = $ leftTypes ->normalize ($ scope );
741- $ normalizedRight = $ rightTypes ->normalize ($ rightScope );
742- $ normalizedLeft = $ this ->propagateArrayDimFetchNarrowingsToParent ($ normalizedLeft , $ scope );
743- $ normalizedRight = $ this ->propagateArrayDimFetchNarrowingsToParent ($ normalizedRight , $ rightScope );
744- $ types = $ normalizedLeft ->intersectWith ($ normalizedRight );
745- }
737+ $ types = $ context ->true () ? $ leftTypes ->unionWith ($ rightTypes ) : $ leftTypes ->normalize ($ scope )->intersectWith ($ rightTypes ->normalize ($ rightScope ));
746738 if ($ context ->false ()) {
747739 $ leftTypesForHolders = $ leftTypes ;
748740 $ rightTypesForHolders = $ rightTypes ;
@@ -796,11 +788,7 @@ public function specifyTypesInCondition(
796788 ) {
797789 $ types = $ leftTypes ->normalize ($ scope );
798790 } else {
799- $ normalizedLeft = $ leftTypes ->normalize ($ scope );
800- $ normalizedRight = $ rightTypes ->normalize ($ rightScope );
801- $ normalizedLeft = $ this ->propagateArrayDimFetchNarrowingsToParent ($ normalizedLeft , $ scope );
802- $ normalizedRight = $ this ->propagateArrayDimFetchNarrowingsToParent ($ normalizedRight , $ rightScope );
803- $ types = $ normalizedLeft ->intersectWith ($ normalizedRight );
791+ $ types = $ leftTypes ->normalize ($ scope )->intersectWith ($ rightTypes ->normalize ($ rightScope ));
804792 $ types = $ this ->augmentBooleanOrTruthyWithConditionalHolders ($ scope , $ rightScope , $ expr , $ types );
805793 }
806794 } else {
@@ -2088,54 +2076,6 @@ private function augmentBooleanOrTruthyWithConditionalHolders(MutatingScope $sco
20882076 return $ types ;
20892077 }
20902078
2091- private function propagateArrayDimFetchNarrowingsToParent (SpecifiedTypes $ normalizedTypes , Scope $ scope ): SpecifiedTypes
2092- {
2093- $ additionalSureTypes = [];
2094- foreach ($ normalizedTypes ->getSureTypes () as $ exprString => [$ exprNode , $ type ]) {
2095- if (
2096- !$ exprNode instanceof ArrayDimFetch
2097- || $ exprNode ->dim === null
2098- || $ exprNode ->var instanceof ArrayDimFetch
2099- ) {
2100- continue ;
2101- }
2102-
2103- $ dimType = $ scope ->getType ($ exprNode ->dim )->toArrayKey ();
2104- if (!$ dimType instanceof ConstantIntegerType && !$ dimType instanceof ConstantStringType) { // @phpstan-ignore phpstanApi.instanceofType
2105- continue ;
2106- }
2107-
2108- $ parentExprString = $ this ->exprPrinter ->printExpr ($ exprNode ->var );
2109- if (isset ($ normalizedTypes ->getSureTypes ()[$ parentExprString ]) || isset ($ additionalSureTypes [$ parentExprString ])) {
2110- continue ;
2111- }
2112-
2113- $ parentType = $ scope ->getType ($ exprNode ->var );
2114- if ($ parentType instanceof MixedType || !$ parentType ->isArray ()->yes ()) {
2115- continue ;
2116- }
2117-
2118- $ narrowedParentType = TypeCombinator::intersect (
2119- $ parentType ,
2120- new HasOffsetValueType ($ dimType , $ type ),
2121- );
2122- if ($ narrowedParentType instanceof NeverType) {
2123- continue ;
2124- }
2125-
2126- $ additionalSureTypes [$ parentExprString ] = [$ exprNode ->var , $ narrowedParentType ];
2127- }
2128-
2129- if ($ additionalSureTypes === []) {
2130- return $ normalizedTypes ;
2131- }
2132-
2133- return new SpecifiedTypes (
2134- $ normalizedTypes ->getSureTypes () + $ additionalSureTypes ,
2135- [],
2136- );
2137- }
2138-
21392079 /**
21402080 * @return array<string, ConditionalExpressionHolder[]>
21412081 */
@@ -2646,6 +2586,42 @@ private function createForExpr(
26462586 }
26472587 }
26482588
2589+ if (
2590+ $ expr instanceof ArrayDimFetch
2591+ && $ expr ->dim !== null
2592+ && !$ context ->null ()
2593+ ) {
2594+ $ dimType = $ scope ->getType ($ expr ->dim );
2595+ if ($ dimType instanceof ConstantIntegerType || $ dimType ->getConstantStrings () !== []) {
2596+ $ varType = $ scope ->getType ($ expr ->var );
2597+ $ constantArrays = $ varType ->getConstantArrays ();
2598+ if ($ constantArrays !== []) {
2599+ $ typesToRemove = [];
2600+ foreach ($ constantArrays as $ constantArray ) {
2601+ if (!$ constantArray ->hasOffsetValueType ($ dimType )->yes ()) {
2602+ continue ;
2603+ }
2604+ $ offsetValueType = $ constantArray ->getOffsetValueType ($ dimType );
2605+ if ($ context ->false ()) {
2606+ if ($ type ->isSuperTypeOf ($ offsetValueType )->yes ()) {
2607+ $ typesToRemove [] = $ constantArray ;
2608+ }
2609+ } elseif ($ context ->true ()) {
2610+ if ($ type ->isSuperTypeOf ($ offsetValueType )->no ()) {
2611+ $ typesToRemove [] = $ constantArray ;
2612+ }
2613+ }
2614+ }
2615+
2616+ if ($ typesToRemove !== [] && count ($ typesToRemove ) < count ($ constantArrays )) {
2617+ $ typeToRemove = TypeCombinator::union (...$ typesToRemove );
2618+ $ varExprString = $ this ->exprPrinter ->printExpr ($ expr ->var );
2619+ $ sureNotTypes [$ varExprString ] = [$ expr ->var , $ typeToRemove ];
2620+ }
2621+ }
2622+ }
2623+ }
2624+
26492625 $ types = new SpecifiedTypes ($ sureTypes , $ sureNotTypes );
26502626 if (isset ($ containsNull ) && !$ containsNull ) {
26512627 return $ this ->createNullsafeTypes ($ originalExpr , $ scope , $ context , $ type )->unionWith ($ types );
0 commit comments