diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt index 06ecaf0fff0..7f95abc9517 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.jvm.codegen.isInlineOnly import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface import org.jetbrains.kotlin.backend.jvm.descriptors.JvmDeclarationFactory import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.hasMangledParameters +import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET @@ -20,6 +21,8 @@ import org.jetbrains.kotlin.ir.builders.Scope import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol @@ -88,6 +91,25 @@ val IrType.erasedUpperBound: IrClass else -> throw IllegalStateException() } +/** + * Get the default null/0 value for the type. + * + * This handles unboxing of non-nullable inline class types to their underlying types and produces + * a null/0 default value for the resulting type. When such unboxing takes place it ensures that + * the value is not reboxed and reunboxed by the codegen by using the unsafeCoerceIntrinsic. + */ +fun IrType.defaultValue(startOffset: Int, endOffset: Int, context: JvmBackendContext): IrExpression { + if (this !is IrSimpleType || hasQuestionMark || classOrNull?.owner?.isInline != true) + return IrConstImpl.defaultValueForType(startOffset, endOffset, this) + + val underlyingType = unboxInlineClass() + val defaultValueForUnderlyingType = IrConstImpl.defaultValueForType(startOffset, endOffset, underlyingType) + return IrCallImpl(startOffset, endOffset, this, context.ir.symbols.unsafeCoerceIntrinsic).also { + it.putTypeArgument(0, underlyingType) // from + it.putTypeArgument(1, this) // to + it.putValueArgument(0, defaultValueForUnderlyingType) + } +} fun IrDeclaration.getJvmNameFromAnnotation(): String? { // TODO lower @JvmName? diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt index b997d36cfd8..078294ab670 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator +import org.jetbrains.kotlin.backend.jvm.ir.defaultValue import org.jetbrains.kotlin.codegen.coroutines.* import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX import org.jetbrains.kotlin.descriptors.Modality @@ -23,7 +24,6 @@ import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.declarations.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl @@ -446,6 +446,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : capturedThisField: IrField?, isStaticSuspendImpl: Boolean ) { + val backendContext = context val invokeSuspend = context.ir.symbols.continuationImplClass.owner.functions .single { it.name == Name.identifier(INVOKE_SUSPEND_METHOD_NAME) } addFunctionOverride(invokeSuspend).also { function -> @@ -481,15 +482,12 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : it.dispatchReceiver = capturedThisValue } irFunction.extensionReceiverParameter?.let { extensionReceiverParameter -> - it.extensionReceiver = IrConstImpl.defaultValueForType( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, extensionReceiverParameter.type + it.extensionReceiver = extensionReceiverParameter.type.defaultValue( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, backendContext ) } for ((i, parameter) in irFunction.valueParameters.withIndex()) { - val defaultValueForParameter = IrConstImpl.defaultValueForType( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, parameter.type - ) - it.putValueArgument(i, defaultValueForParameter) + it.putValueArgument(i, parameter.type.defaultValue(UNDEFINED_OFFSET, UNDEFINED_OFFSET, backendContext)) } if (isStaticSuspendImpl) { it.putValueArgument(0, capturedThisValue) @@ -501,6 +499,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : private fun createStaticSuspendImpl(irFunction: IrSimpleFunction): IrSimpleFunction { // Create static suspend impl method. + val backendContext = context val static = createStaticFunctionWithReceivers( irFunction.parent, irFunction.name.toSuspendImplementationName(), @@ -520,12 +519,14 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : it.putValueArgument(i++, irGet(irFunction.dispatchReceiverParameter!!)) } if (irFunction.extensionReceiverParameter != null) { - it.putValueArgument(i++, irNull()) + val defaultValueForParameter = irFunction.extensionReceiverParameter!!.type.defaultValue( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, backendContext + ) + it.putValueArgument(i++, defaultValueForParameter) + } for (parameter in irFunction.valueParameters) { - val defaultValueForParameter = IrConstImpl.defaultValueForType( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, parameter.type - ) + val defaultValueForParameter = parameter.type.defaultValue(UNDEFINED_OFFSET, UNDEFINED_OFFSET, backendContext) it.putValueArgument(i++, defaultValueForParameter) } }) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmDefaultParameterInjector.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmDefaultParameterInjector.kt index 62f21f8cd11..9f59400fa53 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmDefaultParameterInjector.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmDefaultParameterInjector.kt @@ -7,15 +7,12 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.lower.DefaultParameterInjector import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.ir.defaultValue import org.jetbrains.kotlin.backend.jvm.ir.getJvmVisibilityOfDefaultArgumentStub -import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl -import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.classOrNull class JvmDefaultParameterInjector(context: JvmBackendContext) : DefaultParameterInjector(context, skipInline = false, skipExternalMethods = false) { @@ -26,15 +23,7 @@ class JvmDefaultParameterInjector(context: JvmBackendContext) : nullConst(startOffset, endOffset, irParameter.type) override fun nullConst(startOffset: Int, endOffset: Int, type: IrType): IrExpression { - if (type !is IrSimpleType || type.hasQuestionMark || type.classOrNull?.owner?.isInline != true) - return super.nullConst(startOffset, endOffset, type) - - val underlyingType = type.unboxInlineClass() - return IrCallImpl(startOffset, endOffset, type, context.ir.symbols.unsafeCoerceIntrinsic).apply { - putTypeArgument(0, underlyingType) // from - putTypeArgument(1, type) // to - putValueArgument(0, super.nullConst(startOffset, endOffset, underlyingType)) - } + return type.defaultValue(startOffset, endOffset, context) } override fun defaultArgumentStubVisibility(function: IrFunction) = function.getJvmVisibilityOfDefaultArgumentStub() diff --git a/compiler/testData/codegen/box/inlineClasses/unboxParameterOfSuspendLambdaBeforeInvoke.kt b/compiler/testData/codegen/box/inlineClasses/unboxParameterOfSuspendLambdaBeforeInvoke.kt index 94884f2c806..90260ed9186 100644 --- a/compiler/testData/codegen/box/inlineClasses/unboxParameterOfSuspendLambdaBeforeInvoke.kt +++ b/compiler/testData/codegen/box/inlineClasses/unboxParameterOfSuspendLambdaBeforeInvoke.kt @@ -1,7 +1,7 @@ // IGNORE_BACKEND_FIR: JVM_IR // WITH_COROUTINES // WITH_RUNTIME -// IGNORE_BACKEND: JVM_IR, JS_IR +// IGNORE_BACKEND: JS_IR import helpers.* import kotlin.coroutines.*