From 233987a065ec86e082632ea83a827d5470fac1e0 Mon Sep 17 00:00:00 2001 From: Oleksandr Karpovich Date: Mon, 29 Mar 2021 11:47:26 +0200 Subject: [PATCH] Fix an issue with a default value for extension lambda params in composable functions Example: @Composable fun Foo(attrs: Attr.() -> Unit = {}) {...} Change-Id: I49becd1903ff8a53244601922476c2b33e48a6f4 --- .../kotlin/lower/ComposerParamTransformer.kt | 19 ++++++++++++-- .../lower/decoys/CreateDecoysTransformer.kt | 25 +++++++++++-------- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt index 2774cd2f3de6c..33a5a04ce3e75 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt @@ -21,6 +21,7 @@ import androidx.compose.compiler.plugins.kotlin.analysis.ComposeWritableSlices import androidx.compose.compiler.plugins.kotlin.hasComposableAnnotation import androidx.compose.compiler.plugins.kotlin.irTrace import androidx.compose.compiler.plugins.kotlin.isComposableCallable +import androidx.compose.compiler.plugins.kotlin.lower.decoys.copyWithNewTypeParams import androidx.compose.compiler.plugins.kotlin.lower.decoys.isDecoy import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.ir.copyTo @@ -49,6 +50,7 @@ import org.jetbrains.kotlin.ir.descriptors.WrappedPropertyGetterDescriptor import org.jetbrains.kotlin.ir.descriptors.WrappedPropertySetterDescriptor import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrConstKind import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrGetValue @@ -67,6 +69,7 @@ import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.createType +import org.jetbrains.kotlin.ir.types.isMarkedNullable import org.jetbrains.kotlin.ir.types.isPrimitiveType import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper @@ -267,8 +270,16 @@ class ComposerParamTransformer( endOffset: Int = UNDEFINED_OFFSET ): IrExpression { val classSymbol = classOrNull - if (this !is IrSimpleType || hasQuestionMark || classSymbol?.owner?.isInline != true) + if (this !is IrSimpleType || hasQuestionMark || classSymbol?.owner?.isInline != true) { + if (isMarkedNullable()) { + return IrConstImpl.constNull( + startOffset, + endOffset, + context.irBuiltIns.unitType + ) + } return IrConstImpl.defaultValueForType(startOffset, endOffset, this) + } val klass = classSymbol.owner val ctor = classSymbol.constructors.first() @@ -415,7 +426,11 @@ class ComposerParamTransformer( // case in composable lambdas. The synthetic name that kotlin generates for // anonymous parameters has an issue where it is not safe to dex, so we sanitize // the names here to ensure that dex is always safe. - p.copyTo(fn, name = dexSafeName(p.name)) + p.copyTo( + irFunction = fn, + name = dexSafeName(p.name), + defaultValue = p.defaultValue?.copyWithNewTypeParams(this, fn) + ) } fn.annotations = annotations.map { a -> a } fn.metadata = metadata diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt index ff7f407b987b0..0a6b9fdc7e6f1 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt @@ -22,6 +22,7 @@ import androidx.compose.compiler.plugins.kotlin.lower.ModuleLoweringPass import org.jetbrains.kotlin.backend.common.ir.addChild import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom import org.jetbrains.kotlin.backend.common.ir.copyTo +import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom import org.jetbrains.kotlin.backend.common.ir.moveBodyTo import org.jetbrains.kotlin.backend.common.ir.remapTypeParameters import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder @@ -162,7 +163,7 @@ class CreateDecoysTransformer( newFunction.origin = IrDeclarationOrigin.DEFINED // here generic value parameters will be applied - newFunction.copyParameterDeclarationsFrom(original) + newFunction.copyTypeParametersFrom(original) // ..but we need to remap the return type as well newFunction.returnType = newFunction.returnType.remapTypeParameters( @@ -170,18 +171,22 @@ class CreateDecoysTransformer( target = newFunction ) // remove leading $ in params to avoid confusing other transforms - newFunction.valueParameters = newFunction.valueParameters.map { + newFunction.valueParameters = original.valueParameters.map { val name = dexSafeName(it.name).asString() - if (name.startsWith('$')) { - it.copyTo( - newFunction, - name = Name.identifier(name.dropWhile { it == '$' }) - ) - } else { - it - } + it.copyTo( + newFunction, + name = Name.identifier( + if (name.startsWith('$')) name.dropWhile { it == '$' } else name + ), + defaultValue = it.defaultValue?.copyWithNewTypeParams(original, newFunction) + ) } + newFunction.extensionReceiverParameter = original.extensionReceiverParameter + ?.copyTo(newFunction) + newFunction.dispatchReceiverParameter = original.dispatchReceiverParameter + ?.copyTo(newFunction) + newFunction.body = original.moveBodyTo(newFunction) ?.copyWithNewTypeParams(original, newFunction)