Count recursive local declarations as captures
Local declarations were already counted as captures for composable lambdas before, but the traversal ordering missed the recursive captures, converting some of them into singletons.
Test: Compiler test
Fixes: 318745941
Change-Id: I9097d1be71fb67b73e5027f723fd187c4272f6b4
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/androidUnitTest/kotlin/androidx/compose/compiler/plugins/kotlin/KtxTransformationTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/androidUnitTest/kotlin/androidx/compose/compiler/plugins/kotlin/ComposeBytecodeCodegenTest.kt
similarity index 95%
rename from compose/compiler/compiler-hosted/integration-tests/src/androidUnitTest/kotlin/androidx/compose/compiler/plugins/kotlin/KtxTransformationTest.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/androidUnitTest/kotlin/androidx/compose/compiler/plugins/kotlin/ComposeBytecodeCodegenTest.kt
index a1cfb0c..739cbf2 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/androidUnitTest/kotlin/androidx/compose/compiler/plugins/kotlin/KtxTransformationTest.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/androidUnitTest/kotlin/androidx/compose/compiler/plugins/kotlin/ComposeBytecodeCodegenTest.kt
@@ -16,10 +16,11 @@
package androidx.compose.compiler.plugins.kotlin
+import kotlin.test.assertFalse
import org.junit.Assume.assumeFalse
import org.junit.Test
-class KtxTransformationTest(useFir: Boolean) : AbstractCodegenTest(useFir) {
+class ComposeBytecodeCodegenTest(useFir: Boolean) : AbstractCodegenTest(useFir) {
// b/179279455
// @Test
// fun testObserveLowering() {
@@ -718,4 +719,27 @@
"""
)
}
+
+ @Test
+ fun testRecursiveLocalFunction() = validateBytecode(
+ """
+ import androidx.compose.runtime.*
+
+ @Composable fun Surface(content: @Composable () -> Unit) {}
+
+ @Composable
+ fun MyComposable(){
+ @Composable
+ fun LocalComposable(){
+ Surface { LocalComposable() }
+ }
+ }
+ """,
+ validate = {
+ assertFalse(
+ it.contains("ComposableSingletons"),
+ message = "ComposableSingletons class should not be generated"
+ )
+ }
+ )
}
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/AbstractCodegenTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/AbstractCodegenTest.kt
index 2dd5570..a82b240 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/AbstractCodegenTest.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/jvmTest/kotlin/androidx/compose/compiler/plugins/kotlin/AbstractCodegenTest.kt
@@ -117,9 +117,8 @@
return loader
}
- protected fun testCompile(source: String, dumpClasses: Boolean = false) {
- val loader = createClassLoader(listOf(SourceFile("Test.kt", source)))
- if (dumpClasses) dumpClasses(loader)
+ protected fun testCompile(@Language("kotlin") source: String, dumpClasses: Boolean = false) {
+ classLoader(source, "Test.kt", dumpClasses)
}
protected val COMPOSE_VIEW_STUBS_IMPORTS = """
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
index 99cacc5..f7efc83 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
@@ -428,23 +428,23 @@
!declaration.isInline
val context = FunctionContext(declaration, composable, canRemember)
- declarationContextStack.push(context)
- val result = super.visitFunction(declaration)
- declarationContextStack.pop()
if (declaration.isLocal) {
declarationContextStack.recordLocalDeclaration(context)
}
+ declarationContextStack.push(context)
+ val result = super.visitFunction(declaration)
+ declarationContextStack.pop()
return result
}
override fun visitClass(declaration: IrClass): IrStatement {
val context = ClassContext(declaration)
- declarationContextStack.push(context)
- val result = super.visitClass(declaration)
- declarationContextStack.pop()
if (declaration.isLocal) {
declarationContextStack.recordLocalDeclaration(context)
}
+ declarationContextStack.push(context)
+ val result = super.visitClass(declaration)
+ declarationContextStack.pop()
return result
}