Count unused (anonymous) parameters as real parameters
Underscore parameter is considered unused (or anonymous), but is still a real parameter.
Fixes: 293367137
Test: FunctionalInterfaceTransformTests
Change-Id: I93f14f4e92646955b23312d751f1bb2c5adf5640
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
index f100c5d..e1af9da 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
@@ -4117,4 +4117,38 @@
}
"""
)
+
+ @Test
+ fun test_ComposableLambdaWithUnusedParameter() = verifyComposeIrTransform(
+ source = """
+ import androidx.compose.runtime.*
+
+ val layoutLambda = @Composable { _: Int ->
+ Layout()
+ }
+ """,
+ extra = """
+ import androidx.compose.runtime.*
+
+ @Composable inline fun Layout() {}
+ """,
+ expectedTransformed = """
+ val layoutLambda: Function3<Int, Composer, Int, Unit> = ComposableSingletons%TestKt.lambda-1
+ internal object ComposableSingletons%TestKt {
+ val lambda-1: Function3<Int, Composer, Int, Unit> = composableLambdaInstance(<>, false) { <unused var>: Int, %composer: Composer?, %changed: Int ->
+ if (%changed and 0b01010001 !== 0b00010000 || !%composer.skipping) {
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ Layout(%composer, 0)
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ } else {
+ %composer.skipToGroupEnd()
+ }
+ }
+ }
+ """
+ )
}
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionalInterfaceTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionalInterfaceTransformTests.kt
index 606cc70..98786eb 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionalInterfaceTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionalInterfaceTransformTests.kt
@@ -387,4 +387,88 @@
}
"""
)
+
+ @Test
+ fun testComposableFunInterfaceWAnonymousParam() = verifyComposeIrTransform(
+ """
+ import androidx.compose.runtime.*
+
+ fun interface Consumer {
+ @Composable operator fun invoke(t: Int)
+ }
+
+ @Composable fun Test(int: Int) {
+ Example { _ ->
+ }
+ }
+
+ @Composable fun Example(consumer: Consumer) {
+ }
+ """,
+ """
+ interface Consumer {
+ @Composable
+ abstract fun invoke(t: Int, %composer: Composer?, %changed: Int)
+ }
+ @Composable
+ fun Test(int: Int, %composer: Composer?, %changed: Int) {
+ %composer = %composer.startRestartGroup(<>)
+ sourceInformation(%composer, "C(Test)<Exampl...>:Test.kt")
+ if (%changed and 0b0001 !== 0 || !%composer.skipping) {
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ Example(class <no name provided> : Consumer {
+ @Composable
+ override fun invoke(<unused var>: Int, %composer: Composer?, %changed: Int) {
+ %composer = %composer.startRestartGroup(<>)
+ sourceInformation(%composer, "C(invoke):Test.kt")
+ if (%changed and 0b0001 !== 0 || !%composer.skipping) {
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ Unit
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ } else {
+ %composer.skipToGroupEnd()
+ }
+ val tmp0_rcvr = <this>
+ %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+ tmp0_rcvr.invoke(<unused var>, %composer, updateChangedFlags(%changed or 0b0001))
+ }
+ }
+ }
+ <no name provided>(), %composer, 0)
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ } else {
+ %composer.skipToGroupEnd()
+ }
+ %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+ Test(int, %composer, updateChangedFlags(%changed or 0b0001))
+ }
+ }
+ @Composable
+ fun Example(consumer: Consumer, %composer: Composer?, %changed: Int) {
+ %composer = %composer.startRestartGroup(<>)
+ sourceInformation(%composer, "C(Example):Test.kt")
+ if (%changed and 0b0001 !== 0 || !%composer.skipping) {
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ } else {
+ %composer.skipToGroupEnd()
+ }
+ %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+ Example(consumer, %composer, updateChangedFlags(%changed or 0b0001))
+ }
+ }
+ """
+ )
}
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
index e334859..07c13e3 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
@@ -1689,12 +1689,20 @@
)
if (defaultParam == null) {
- require(parameterCount == defaultIndex) // param count is 1-based, index is 0-based
+ // param count is 1-based, index is 0-based
+ require(parameterCount == defaultIndex) {
+ "Expected $defaultIndex params for ${function.fqNameWhenAvailable}, " +
+ "found $parameterCount"
+ }
} else {
+ val expectedParamCount = defaultIndex +
+ defaultParamCount(contextParameterCount + numRealValueParameters)
require(
- parameterCount == defaultIndex +
- defaultParamCount(contextParameterCount + numRealValueParameters)
- )
+ parameterCount == expectedParamCount
+ ) {
+ "Expected $expectedParamCount params for ${function.fqNameWhenAvailable}, " +
+ "found $parameterCount"
+ }
}
val lambda = irLambdaExpression(
@@ -3875,7 +3883,6 @@
paramName.startsWith(KtxNameConventions.CHANGED_PARAMETER.identifier) ->
changedParams += param
paramName.startsWith("\$context_receiver_") ||
- paramName.startsWith("\$anonymous\$parameter") ||
paramName.startsWith("\$name\$for\$destructuring") ||
paramName.startsWith("\$noName_") ||
paramName == "\$this" -> Unit
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
index 04c7f2c..841ab83a 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
@@ -1572,7 +1572,8 @@
get() = when {
// FIR generates both <iterator> and tmp0_for_iterator...
origin == IrDeclarationOrigin.FOR_LOOP_ITERATOR -> "<iterator>"
- !useFir && origin == IrDeclarationOrigin.UNDERSCORE_PARAMETER -> "<unused var>"
+ // $anonymous$parameter$x vs $unused$var$x
+ origin == IrDeclarationOrigin.UNDERSCORE_PARAMETER -> "<unused var>"
!useFir && name.asString().endsWith("_elvis_lhs") -> "<elvis>"
!useFir && name.asString() == "\$this\$null" -> "<this>"
else -> name.asString()
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
index 93604d6..e905ca7 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
@@ -1953,11 +1953,12 @@
// This simulates a child that recomposes, for example due to a transition.
content(offset.value)
}
- val assumeLayoutBeforeDraw = @Composable { _: Int ->
+ val assumeLayoutBeforeDraw = @Composable { value: Int ->
// This assumes a layout was done before the draw pass.
Layout(
content = {},
modifier = Modifier.drawBehind {
+ assertEquals(offset.value, value)
assertTrue(laidOut)
latch.countDown()
}