diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt index 698cf505b33..b307fe1711d 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt @@ -197,7 +197,7 @@ fun IrFunction.copyValueParametersInsertingContinuationFrom(from: IrFunction, in var additionalShift = 0 from.valueParameters.forEach { // The continuation parameter goes before the default argument mask and handler. - if (it.origin == IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION) { + if (it.origin == IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION && additionalShift == 0) { insertContinuation() additionalShift = 1 } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt index 4b7f1464a7c..4d5e539f989 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt @@ -167,7 +167,7 @@ private fun IrFunction.suspendFunctionView(context: JvmBackendContext): IrFuncti it.copyTypeParametersFrom(this) // Copy the value parameters and insert the continuation parameter. The continuation parameter - // goes before the default argument mask and handler for default argument stubs. + // goes before the default argument mask(s) and handler for default argument stubs. // TODO: It would be nice if AddContinuationLowering could insert the continuation argument before default stub generation. // That would avoid the reshuffling both here and in createSuspendFunctionClassViewIfNeeded. var continuationValueParam: IrValueParameter? = null @@ -203,9 +203,9 @@ internal fun IrCall.createSuspendFunctionCallViewIfNeeded( it.copyTypeArgumentsFrom(this) it.dispatchReceiver = dispatchReceiver it.extensionReceiver = extensionReceiver - // Locate the caller continuation parameter. The continuation parameter is before default argument mask and handler params. - val callerHasDefaultMask = caller.valueParameters.lastOrNull()?.origin == IrDeclarationOrigin.METHOD_HANDLER_IN_DEFAULT_FUNCTION - val callerContinuationIndex = caller.valueParameters.size - 1 - (if (callerHasDefaultMask) 2 else 0) + // Locate the caller continuation parameter. The continuation parameter is before default argument mask(s) and handler params. + val callerNumberOfMasks = caller.valueParameters.count { it.origin == IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION } + val callerContinuationIndex = caller.valueParameters.size - 1 - (if (callerNumberOfMasks != 0) callerNumberOfMasks + 1 else 0) val continuationParameter = when { caller.isInvokeSuspendOfLambda() || caller.isInvokeSuspendOfContinuation() || @@ -215,16 +215,17 @@ internal fun IrCall.createSuspendFunctionCallViewIfNeeded( else -> IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, caller.valueParameters[callerContinuationIndex].symbol) } // If the suspend function view that we are calling has default parameters, we need to make sure to pass the - // continuation before the default parameter mask and handler. - val hasDefaultMask = view.valueParameters.last().origin == IrDeclarationOrigin.METHOD_HANDLER_IN_DEFAULT_FUNCTION - val continuationIndex = valueArgumentsCount - (if (hasDefaultMask) 2 else 0) + // continuation before the default parameter mask(s) and handler. + val numberOfMasks = view.valueParameters.count { it.origin == IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION } + val continuationIndex = valueArgumentsCount - (if (numberOfMasks != 0) numberOfMasks + 1 else 0) for (i in 0 until continuationIndex) { it.putValueArgument(i, getValueArgument(i)) } it.putValueArgument(continuationIndex, continuationParameter) - if (hasDefaultMask) { - it.putValueArgument(valueArgumentsCount - 1, getValueArgument(continuationIndex)) - it.putValueArgument(valueArgumentsCount, getValueArgument(continuationIndex + 1)) + if (numberOfMasks != 0) { + for (i in 0 until numberOfMasks + 1) { + it.putValueArgument(valueArgumentsCount + i - 1, getValueArgument(continuationIndex + i)) + } } } } diff --git a/compiler/testData/codegen/box/coroutines/reflect/callSuspendBy.kt b/compiler/testData/codegen/box/coroutines/reflect/callSuspendBy.kt index 640c0123999..9d7019479e8 100644 --- a/compiler/testData/codegen/box/coroutines/reflect/callSuspendBy.kt +++ b/compiler/testData/codegen/box/coroutines/reflect/callSuspendBy.kt @@ -24,6 +24,43 @@ fun ordinary() = "OK" suspend fun withDefault(s: String = "OK") = s +suspend fun withManyDefault( + s0: String = "NOT OK 0", + s1: String = "NOT OK 1", + s2: String = "NOT OK 2", + s3: String = "NOT OK 3", + s4: String = "NOT OK 4", + s5: String = "NOT OK 5", + s6: String = "NOT OK 6", + s7: String = "NOT OK 7", + s8: String = "NOT OK 8", + s9: String = "NOT OK 9", + s10: String = "NOT OK 10", + s11: String = "NOT OK 11", + s12: String = "NOT OK 12", + s13: String = "NOT OK 13", + s14: String = "NOT OK 14", + s15: String = "NOT OK 15", + s16: String = "NOT OK 16", + s17: String = "NOT OK 17", + s18: String = "NOT OK 18", + s19: String = "NOT OK 19", + s20: String = "NOT OK 20", + s21: String = "NOT OK 21", + s22: String = "NOT OK 22", + s23: String = "NOT OK 23", + s24: String = "NOT OK 24", + s25: String = "NOT OK 25", + s26: String = "NOT OK 26", + s27: String = "NOT OK 27", + s28: String = "NOT OK 28", + s29: String = "NOT OK 29", + s30: String = "NOT OK 30", + s31: String = "NOT OK 31", + s32: String = "NOT OK 32", + ok: String = "OK" +) = ok + var log = "" var proceed = {} @@ -64,6 +101,10 @@ fun box(): String { builder { res = ::withDefault.callSuspendBy(emptyMap()) as String? } + if (res != "OK") return res ?: "FAIL 5" + builder { + res = ::withManyDefault.callSuspendBy(emptyMap()) as String? + } builder { ::suspending.callSuspendBy(emptyMap()) }