@@ -2405,6 +2405,14 @@ private function createForExpr(
24052405 }
24062406 }
24072407
2408+ if ($ this ->subExpressionsHaveSideEffects ($ expr , $ scope )) {
2409+ if (isset ($ containsNull ) && !$ containsNull ) {
2410+ return $ this ->createNullsafeTypes ($ originalExpr , $ scope , $ context , $ type );
2411+ }
2412+
2413+ return new SpecifiedTypes ([], []);
2414+ }
2415+
24082416 $ sureTypes = [];
24092417 $ sureNotTypes = [];
24102418 if ($ context ->false ()) {
@@ -2433,6 +2441,149 @@ private function createForExpr(
24332441 return $ types ;
24342442 }
24352443
2444+ private function subExpressionsHaveSideEffects (Expr $ expr , Scope $ scope ): bool
2445+ {
2446+ if (
2447+ $ expr instanceof MethodCall
2448+ || $ expr instanceof Expr \NullsafeMethodCall
2449+ || $ expr instanceof PropertyFetch
2450+ || $ expr instanceof Expr \NullsafePropertyFetch
2451+ || $ expr instanceof ArrayDimFetch
2452+ ) {
2453+ if ($ this ->expressionHasSideEffects ($ expr ->var , $ scope )) {
2454+ return true ;
2455+ }
2456+ } elseif (
2457+ $ expr instanceof StaticCall
2458+ || $ expr instanceof StaticPropertyFetch
2459+ ) {
2460+ if ($ expr ->class instanceof Expr && $ this ->expressionHasSideEffects ($ expr ->class , $ scope )) {
2461+ return true ;
2462+ }
2463+ }
2464+
2465+ if ($ expr instanceof Expr \CallLike && !$ expr ->isFirstClassCallable ()) {
2466+ foreach ($ expr ->getArgs () as $ arg ) {
2467+ if ($ this ->expressionHasSideEffects ($ arg ->value , $ scope )) {
2468+ return true ;
2469+ }
2470+ }
2471+ }
2472+
2473+ return false ;
2474+ }
2475+
2476+ private function expressionHasSideEffects (Expr $ expr , Scope $ scope ): bool
2477+ {
2478+ if ($ expr instanceof Expr \New_) {
2479+ return true ;
2480+ }
2481+
2482+ if ($ expr instanceof FuncCall) {
2483+ if ($ expr ->isFirstClassCallable ()) {
2484+ return false ;
2485+ }
2486+ if ($ expr ->name instanceof Name) {
2487+ if (!$ this ->reflectionProvider ->hasFunction ($ expr ->name , $ scope )) {
2488+ return true ;
2489+ }
2490+ $ functionReflection = $ this ->reflectionProvider ->getFunction ($ expr ->name , $ scope );
2491+ $ hasSideEffects = $ functionReflection ->hasSideEffects ();
2492+ if ($ hasSideEffects ->yes ()) {
2493+ return true ;
2494+ }
2495+ if (!$ this ->rememberPossiblyImpureFunctionValues && !$ hasSideEffects ->no ()) {
2496+ return true ;
2497+ }
2498+ } else {
2499+ return true ;
2500+ }
2501+ foreach ($ expr ->getArgs () as $ arg ) {
2502+ if ($ this ->expressionHasSideEffects ($ arg ->value , $ scope )) {
2503+ return true ;
2504+ }
2505+ }
2506+ return false ;
2507+ }
2508+
2509+ if ($ expr instanceof MethodCall || $ expr instanceof Expr \NullsafeMethodCall) {
2510+ if ($ expr ->isFirstClassCallable ()) {
2511+ return $ this ->expressionHasSideEffects ($ expr ->var , $ scope );
2512+ }
2513+ if ($ expr ->name instanceof Node \Identifier) {
2514+ $ calledOnType = $ scope ->getType ($ expr ->var );
2515+ $ methodReflection = $ scope ->getMethodReflection ($ calledOnType , $ expr ->name ->toString ());
2516+ if (
2517+ $ methodReflection === null
2518+ || $ methodReflection ->hasSideEffects ()->yes ()
2519+ || (!$ this ->rememberPossiblyImpureFunctionValues && !$ methodReflection ->hasSideEffects ()->no ())
2520+ ) {
2521+ return true ;
2522+ }
2523+ } else {
2524+ return true ;
2525+ }
2526+ foreach ($ expr ->getArgs () as $ arg ) {
2527+ if ($ this ->expressionHasSideEffects ($ arg ->value , $ scope )) {
2528+ return true ;
2529+ }
2530+ }
2531+ return $ this ->expressionHasSideEffects ($ expr ->var , $ scope );
2532+ }
2533+
2534+ if ($ expr instanceof StaticCall) {
2535+ if ($ expr ->isFirstClassCallable ()) {
2536+ if ($ expr ->class instanceof Expr) {
2537+ return $ this ->expressionHasSideEffects ($ expr ->class , $ scope );
2538+ }
2539+ return false ;
2540+ }
2541+ if ($ expr ->name instanceof Node \Identifier) {
2542+ if ($ expr ->class instanceof Name) {
2543+ $ calledOnType = $ scope ->resolveTypeByName ($ expr ->class );
2544+ } else {
2545+ $ calledOnType = $ scope ->getType ($ expr ->class );
2546+ }
2547+ $ methodReflection = $ scope ->getMethodReflection ($ calledOnType , $ expr ->name ->toString ());
2548+ if (
2549+ $ methodReflection === null
2550+ || $ methodReflection ->hasSideEffects ()->yes ()
2551+ || (!$ this ->rememberPossiblyImpureFunctionValues && !$ methodReflection ->hasSideEffects ()->no ())
2552+ ) {
2553+ return true ;
2554+ }
2555+ } else {
2556+ return true ;
2557+ }
2558+ foreach ($ expr ->getArgs () as $ arg ) {
2559+ if ($ this ->expressionHasSideEffects ($ arg ->value , $ scope )) {
2560+ return true ;
2561+ }
2562+ }
2563+ if ($ expr ->class instanceof Expr) {
2564+ return $ this ->expressionHasSideEffects ($ expr ->class , $ scope );
2565+ }
2566+ return false ;
2567+ }
2568+
2569+ if ($ expr instanceof PropertyFetch || $ expr instanceof Expr \NullsafePropertyFetch) {
2570+ return $ this ->expressionHasSideEffects ($ expr ->var , $ scope );
2571+ }
2572+
2573+ if ($ expr instanceof ArrayDimFetch) {
2574+ return $ this ->expressionHasSideEffects ($ expr ->var , $ scope );
2575+ }
2576+
2577+ if ($ expr instanceof StaticPropertyFetch) {
2578+ if ($ expr ->class instanceof Expr) {
2579+ return $ this ->expressionHasSideEffects ($ expr ->class , $ scope );
2580+ }
2581+ return false ;
2582+ }
2583+
2584+ return false ;
2585+ }
2586+
24362587 private function createNullsafeTypes (Expr $ expr , Scope $ scope , TypeSpecifierContext $ context , ?Type $ type ): SpecifiedTypes
24372588 {
24382589 if ($ expr instanceof Expr \NullsafePropertyFetch) {
0 commit comments