Always force recompose if parent providers of Composition have changed

Forces full recomposition if composition local map provided by parent composition has been updated.

Fixes: 258089076
Test: SubcomposeLayoutTest

Change-Id: I86ec7162e9b7ff0c55e30ca85d79139ac7bd1190
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
index 03e25a0..65ee2ec 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
@@ -3314,7 +3314,7 @@
                         invokeComposable(this, content)
                         endGroup()
                     } else if (
-                        forciblyRecompose &&
+                        (forciblyRecompose || providersInvalid) &&
                         savedContent != null &&
                         savedContent != Composer.Empty
                     ) {
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt
index a71891f..f3a63ae 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt
@@ -64,6 +64,7 @@
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.zIndex
@@ -1198,6 +1199,57 @@
     }
 
     @Test
+    fun staticCompositionLocalChangeInMainComposition_withNonStaticLocal_invalidatesComposition() {
+        var isDark by mutableStateOf(false)
+
+        val staticLocal = staticCompositionLocalOf<Boolean> { error("Not defined") }
+        val local = compositionLocalOf<Boolean> { error("Not defined") }
+        val innerLocal = staticCompositionLocalOf<Unit> { error("\not defined") }
+
+        val content = @Composable {
+            CompositionLocalProvider(innerLocal provides Unit) {
+                val value1 = staticLocal.current
+                val value2 = local.current
+                Box(
+                    Modifier
+                        .testTag(if (value1) "dark" else "light")
+                        .requiredSize(if (value2) 50.dp else 100.dp)
+                )
+            }
+        }
+
+        rule.setContent {
+            CompositionLocalProvider(
+                staticLocal provides isDark,
+            ) {
+                CompositionLocalProvider(
+                    local provides staticLocal.current
+                ) {
+                    SubcomposeLayout { constraints ->
+                        val measurables = subcompose(Unit, content)
+                        val placeables = measurables.map {
+                            it.measure(constraints)
+                        }
+                        layout(100, 100) {
+                            placeables.forEach { it.place(IntOffset.Zero) }
+                        }
+                    }
+                }
+            }
+        }
+
+        rule.onNodeWithTag("light")
+            .assertWidthIsEqualTo(100.dp)
+
+        isDark = true
+
+        rule.waitForIdle()
+
+        rule.onNodeWithTag("dark")
+            .assertWidthIsEqualTo(50.dp)
+    }
+
+    @Test
     fun derivedStateChangeInMainCompositionRecomposesSubcomposition() {
         var flag by mutableStateOf(true)
         var subcomposionValue: Boolean? = null