Merge "Fix composition locals that are provided in a nested scope" into androidx-main
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 674fab2..f8ace7f 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
@@ -2350,6 +2350,9 @@
// Invoke the scope's composition function
firstInRange.scope.compose(this)
+ // We could have moved out of a provider so the provider cache is invalid.
+ providerCache = null
+
// Restore the parent of the reader to the previous parent
reader.restoreParent(parent)
} else {
diff --git a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
index 64c54a5..468fd71 100644
--- a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
+++ b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
@@ -18,11 +18,13 @@
import androidx.compose.runtime.external.kotlinx.collections.immutable.persistentHashMapOf
import androidx.compose.runtime.mock.EmptyApplier
+import androidx.compose.runtime.mock.MockViewValidator
import androidx.compose.runtime.mock.TestMonotonicFrameClock
import androidx.compose.runtime.mock.Text
import androidx.compose.runtime.mock.compositionTest
import androidx.compose.runtime.mock.expectChanges
import androidx.compose.runtime.mock.expectNoChanges
+import androidx.compose.runtime.mock.revalidate
import androidx.compose.runtime.mock.validate
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
@@ -46,6 +48,7 @@
// Create a static CompositionLocal with an int value
val LocalSomeStaticInt = staticCompositionLocalOf { 40 }
+@Stable
class CompositionLocalTests {
@Composable
@@ -643,6 +646,51 @@
advance()
assertEquals(setOf(0, 0, 0), actualValues)
}
+
+ @Test // Regression test for b/233064044
+ fun testRecomposeCacheInvalidation() = compositionTest {
+ var state = mutableStateOf(0)
+
+ compose {
+ CacheInvalidate(state)
+ }
+
+ validate {
+ this.CacheInvalidate(state)
+ }
+
+ state.value++
+ advance()
+
+ revalidate()
+ }
+}
+
+val cacheLocal = staticCompositionLocalOf { "Unset" }
+@Composable
+fun CacheInvalidate(state: State<Int>) {
+ Text("${state.value}")
+ Text(cacheLocal.current)
+ CacheInvalidateSet {
+ Text("${state.value}")
+ Text(cacheLocal.current)
+ }
+ Text(cacheLocal.current)
+}
+
+@Composable
+fun CacheInvalidateSet(content: @Composable () -> Unit) {
+ CompositionLocalProvider(cacheLocal provides "Set") {
+ content()
+ }
+}
+
+fun MockViewValidator.CacheInvalidate(state: State<Int>) {
+ Text("${state.value}")
+ Text("Unset")
+ Text("${state.value}")
+ Text("Set")
+ Text("Unset")
}
data class SomeData(val value: String = "default")