@@ -2584,7 +2584,7 @@ public function assignVariable(string $variableName, Type $type, Type $nativeTyp
25842584 $ scope ->nativeExpressionTypes [$ exprString ] = new ExpressionTypeHolder ($ node , $ nativeType , $ certainty );
25852585 }
25862586
2587- foreach ($ scope ->expressionTypes as $ expressionType ) {
2587+ foreach ($ scope ->expressionTypes as $ exprString => $ expressionType ) {
25882588 if (!$ expressionType ->getExpr () instanceof IntertwinedVariableByReferenceWithExpr) {
25892589 continue ;
25902590 }
@@ -2595,6 +2595,16 @@ public function assignVariable(string $variableName, Type $type, Type $nativeTyp
25952595 continue ;
25962596 }
25972597
2598+ $ assignedExpr = $ expressionType ->getExpr ()->getAssignedExpr ();
2599+ if (
2600+ $ assignedExpr instanceof Expr \ArrayDimFetch
2601+ && !$ this ->isDimFetchPathReachable ($ scope , $ assignedExpr )
2602+ ) {
2603+ unset($ scope ->expressionTypes [$ exprString ]);
2604+ unset($ scope ->nativeExpressionTypes [$ exprString ]);
2605+ continue ;
2606+ }
2607+
25982608 $ has = $ scope ->hasExpressionType ($ expressionType ->getExpr ()->getExpr ());
25992609 if (
26002610 $ expressionType ->getExpr ()->getExpr () instanceof Variable
@@ -2613,18 +2623,41 @@ public function assignVariable(string $variableName, Type $type, Type $nativeTyp
26132623 array_merge ($ intertwinedPropagatedFrom , [$ variableName ]),
26142624 );
26152625 } else {
2626+ $ targetRootVar = $ this ->getIntertwinedRefRootVariableName ($ expressionType ->getExpr ()->getExpr ());
2627+ if ($ targetRootVar !== null && in_array ($ targetRootVar , $ intertwinedPropagatedFrom , true )) {
2628+ continue ;
2629+ }
26162630 $ scope = $ scope ->assignExpression (
26172631 $ expressionType ->getExpr ()->getExpr (),
26182632 $ scope ->getType ($ expressionType ->getExpr ()->getAssignedExpr ()),
26192633 $ scope ->getNativeType ($ expressionType ->getExpr ()->getAssignedExpr ()),
26202634 );
26212635 }
2622-
26232636 }
26242637
26252638 return $ scope ;
26262639 }
26272640
2641+ private function isDimFetchPathReachable (self $ scope , Expr \ArrayDimFetch $ dimFetch ): bool
2642+ {
2643+ if ($ dimFetch ->dim === null ) {
2644+ return false ;
2645+ }
2646+
2647+ if (!$ dimFetch ->var instanceof Expr \ArrayDimFetch) {
2648+ return true ;
2649+ }
2650+
2651+ $ varType = $ scope ->getType ($ dimFetch ->var );
2652+ $ dimType = $ scope ->getType ($ dimFetch ->dim );
2653+
2654+ if (!$ varType ->hasOffsetValueType ($ dimType )->yes ()) {
2655+ return false ;
2656+ }
2657+
2658+ return $ this ->isDimFetchPathReachable ($ scope , $ dimFetch ->var );
2659+ }
2660+
26282661 private function unsetExpression (Expr $ expr ): self
26292662 {
26302663 $ scope = $ this ;
@@ -2835,12 +2868,6 @@ public function invalidateExpression(Expr $expressionToInvalidate, bool $require
28352868
28362869 foreach ($ expressionTypes as $ exprString => $ exprTypeHolder ) {
28372870 $ exprExpr = $ exprTypeHolder ->getExpr ();
2838- if (
2839- $ exprExpr instanceof IntertwinedVariableByReferenceWithExpr
2840- && $ exprExpr ->isVariableToVariableReference ()
2841- ) {
2842- continue ;
2843- }
28442871 if (!$ this ->shouldInvalidateExpression ($ exprStringToInvalidate , $ expressionToInvalidate , $ exprExpr , $ exprString , $ requireMoreCharacters , $ invalidatingClass )) {
28452872 continue ;
28462873 }
@@ -2908,8 +2935,32 @@ public function invalidateExpression(Expr $expressionToInvalidate, bool $require
29082935 );
29092936 }
29102937
2938+ private function getIntertwinedRefRootVariableName (Expr $ expr ): ?string
2939+ {
2940+ if ($ expr instanceof Variable && is_string ($ expr ->name )) {
2941+ return $ expr ->name ;
2942+ }
2943+ if ($ expr instanceof Expr \ArrayDimFetch) {
2944+ return $ this ->getIntertwinedRefRootVariableName ($ expr ->var );
2945+ }
2946+ return null ;
2947+ }
2948+
29112949 private function shouldInvalidateExpression (string $ exprStringToInvalidate , Expr $ exprToInvalidate , Expr $ expr , string $ exprString , bool $ requireMoreCharacters = false , ?ClassReflection $ invalidatingClass = null ): bool
29122950 {
2951+ if (
2952+ $ expr instanceof IntertwinedVariableByReferenceWithExpr
2953+ && $ exprToInvalidate instanceof Variable
2954+ && is_string ($ exprToInvalidate ->name )
2955+ && (
2956+ $ expr ->getVariableName () === $ exprToInvalidate ->name
2957+ || $ this ->getIntertwinedRefRootVariableName ($ expr ->getExpr ()) === $ exprToInvalidate ->name
2958+ || $ this ->getIntertwinedRefRootVariableName ($ expr ->getAssignedExpr ()) === $ exprToInvalidate ->name
2959+ )
2960+ ) {
2961+ return false ;
2962+ }
2963+
29132964 if ($ requireMoreCharacters && $ exprStringToInvalidate === $ exprString ) {
29142965 return false ;
29152966 }
0 commit comments