diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxInlineCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxInlineCodegenTestGenerated.java index 4b18916e8c1..9d7320fa67c 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxInlineCodegenTestGenerated.java @@ -4981,12 +4981,24 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("returnBoxedFromLambda.kt") + public void testReturnBoxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt"); + } + @Test @TestMetadata("returnUnboxedDirect.kt") public void testReturnUnboxedDirect() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); } + @Test + @TestMetadata("returnUnboxedFromLambda.kt") + public void testReturnUnboxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt"); + } + @Test @TestMetadata("returnUnboxedResume.kt") public void testReturnUnboxedResume() throws Exception { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt index b9de564ba7a..456383789bf 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType import org.jetbrains.kotlin.backend.jvm.ir.isInlineParameter import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi +import org.jetbrains.kotlin.backend.jvm.lower.suspendFunctionOriginal import org.jetbrains.kotlin.codegen.IrExpressionLambda import org.jetbrains.kotlin.codegen.JvmKotlinType import org.jetbrains.kotlin.codegen.StackValue @@ -215,11 +216,18 @@ class IrExpressionLambdaImpl( val isSuspend = parameter.isInlineParameter() && parameter.type.isSuspendFunctionTypeOrSubtype() capturedParamDesc(parameter.name.asString(), asmMethod.argumentTypes[startCapture + index], isSuspend) } + // The parameter list should include the continuation if this is a suspend lambda. In the IR backend, + // the lambda is suspend iff the inline function's parameter is marked suspend, so FunctionN.invoke call + // inside the inline function already has a (real) continuation value as the last argument. val freeParameters = function.explicitParameters.let { it.take(startCapture) + it.drop(endCapture) } val freeAsmParameters = asmMethod.argumentTypes.let { it.take(startCapture) + it.drop(endCapture) } - invokeMethod = Method(asmMethod.name, asmMethod.returnType, freeAsmParameters.toTypedArray()) + // The return type, on the other hand, should be the original type if this is a suspend lambda that returns + // an unboxed inline class value so that the inliner will box it (FunctionN.invoke should return a boxed value). + val unboxedReturnType = function.suspendFunctionOriginal().originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass() + val unboxedAsmReturnType = unboxedReturnType?.let(codegen.typeMapper::mapType) + invokeMethod = Method(asmMethod.name, unboxedAsmReturnType ?: asmMethod.returnType, freeAsmParameters.toTypedArray()) invokeMethodParameters = freeParameters.map { it.type.toIrBasedKotlinType() } - invokeMethodReturnType = function.returnType.toIrBasedKotlinType() + invokeMethodReturnType = (unboxedReturnType ?: function.returnType).toIrBasedKotlinType() } } diff --git a/compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt b/compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt new file mode 100644 index 00000000000..d8cb8dd8233 --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt @@ -0,0 +1,20 @@ +// WITH_RUNTIME +// WITH_COROUTINES +// IGNORE_BACKEND: JS_IR +// FILE: 1.kt +inline fun (suspend () -> T).map(crossinline transform: suspend (T) -> R): suspend () -> R = + { transform(this()) } + +// FILE: 2.kt +import helpers.* +import kotlin.coroutines.* + +inline class C(val value: Int) + +fun box(): String { + var result = 0 + suspend { + result = suspend { C(1) as C? }.map { it }()?.value ?: 2 + }.startCoroutine(EmptyContinuation) + return if (result == 1) "OK" else "fail: $result" +} diff --git a/compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt b/compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt new file mode 100644 index 00000000000..890aa8c8812 --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt @@ -0,0 +1,20 @@ +// WITH_RUNTIME +// WITH_COROUTINES +// IGNORE_BACKEND: JS_IR +// FILE: 1.kt +inline fun (suspend () -> T).map(crossinline transform: suspend (T) -> R): suspend () -> R = + { transform(this()) } + +// FILE: 2.kt +import helpers.* +import kotlin.coroutines.* + +inline class C(val value: String) + +fun box(): String { + var result = "fail" + suspend { + result = suspend { C("OK") }.map { it }().value + }.startCoroutine(EmptyContinuation) + return result +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxInlineCodegenTestGenerated.java index 291d0aff4bf..321fc2c65e4 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -4981,12 +4981,24 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @Test + @TestMetadata("returnBoxedFromLambda.kt") + public void testReturnBoxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt"); + } + @Test @TestMetadata("returnUnboxedDirect.kt") public void testReturnUnboxedDirect() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); } + @Test + @TestMetadata("returnUnboxedFromLambda.kt") + public void testReturnUnboxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt"); + } + @Test @TestMetadata("returnUnboxedResume.kt") public void testReturnUnboxedResume() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index 16622ea23ab..6aa08ae21bc 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -4981,12 +4981,24 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @Test + @TestMetadata("returnBoxedFromLambda.kt") + public void testReturnBoxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt"); + } + @Test @TestMetadata("returnUnboxedDirect.kt") public void testReturnUnboxedDirect() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); } + @Test + @TestMetadata("returnUnboxedFromLambda.kt") + public void testReturnUnboxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt"); + } + @Test @TestMetadata("returnUnboxedResume.kt") public void testReturnUnboxedResume() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxInlineCodegenTestGenerated.java index 09234c72aa1..4c1178685b3 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxInlineCodegenTestGenerated.java @@ -4981,12 +4981,24 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("returnBoxedFromLambda.kt") + public void testReturnBoxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt"); + } + @Test @TestMetadata("returnUnboxedDirect.kt") public void testReturnUnboxedDirect() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); } + @Test + @TestMetadata("returnUnboxedFromLambda.kt") + public void testReturnUnboxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt"); + } + @Test @TestMetadata("returnUnboxedResume.kt") public void testReturnUnboxedResume() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrCompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrCompileKotlinAgainstInlineKotlinTestGenerated.java index bde6f41cc1a..77bf5d03051 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrCompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrCompileKotlinAgainstInlineKotlinTestGenerated.java @@ -4981,12 +4981,24 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("returnBoxedFromLambda.kt") + public void testReturnBoxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt"); + } + @Test @TestMetadata("returnUnboxedDirect.kt") public void testReturnUnboxedDirect() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); } + @Test + @TestMetadata("returnUnboxedFromLambda.kt") + public void testReturnUnboxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt"); + } + @Test @TestMetadata("returnUnboxedResume.kt") public void testReturnUnboxedResume() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/JvmIrAgainstOldBoxInlineTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/JvmIrAgainstOldBoxInlineTestGenerated.java index e6e0817715d..831f5c3847b 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/JvmIrAgainstOldBoxInlineTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/JvmIrAgainstOldBoxInlineTestGenerated.java @@ -4981,12 +4981,24 @@ public class JvmIrAgainstOldBoxInlineTestGenerated extends AbstractJvmIrAgainstO KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_MULTI_MODULE_IR_AGAINST_OLD, true); } + @Test + @TestMetadata("returnBoxedFromLambda.kt") + public void testReturnBoxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt"); + } + @Test @TestMetadata("returnUnboxedDirect.kt") public void testReturnUnboxedDirect() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); } + @Test + @TestMetadata("returnUnboxedFromLambda.kt") + public void testReturnUnboxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt"); + } + @Test @TestMetadata("returnUnboxedResume.kt") public void testReturnUnboxedResume() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/JvmOldAgainstIrBoxInlineTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/JvmOldAgainstIrBoxInlineTestGenerated.java index 84e730a83a2..4e57f4dc68d 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/JvmOldAgainstIrBoxInlineTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/JvmOldAgainstIrBoxInlineTestGenerated.java @@ -4981,12 +4981,24 @@ public class JvmOldAgainstIrBoxInlineTestGenerated extends AbstractJvmOldAgainst KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_MULTI_MODULE_OLD_AGAINST_IR, true); } + @Test + @TestMetadata("returnBoxedFromLambda.kt") + public void testReturnBoxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt"); + } + @Test @TestMetadata("returnUnboxedDirect.kt") public void testReturnUnboxedDirect() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); } + @Test + @TestMetadata("returnUnboxedFromLambda.kt") + public void testReturnUnboxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt"); + } + @Test @TestMetadata("returnUnboxedResume.kt") public void testReturnUnboxedResume() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java index 548ed25055e..a7b586fc00e 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java @@ -3990,11 +3990,21 @@ public class IrJsCodegenInlineES6TestGenerated extends AbstractIrJsCodegenInline KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true); } + @TestMetadata("returnBoxedFromLambda.kt") + public void testReturnBoxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt"); + } + @TestMetadata("returnUnboxedDirect.kt") public void testReturnUnboxedDirect() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); } + @TestMetadata("returnUnboxedFromLambda.kt") + public void testReturnUnboxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt"); + } + @TestMetadata("returnUnboxedResume.kt") public void testReturnUnboxedResume() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java index b49c1853f7c..e7de839e212 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java @@ -3990,11 +3990,21 @@ public class IrJsCodegenInlineTestGenerated extends AbstractIrJsCodegenInlineTes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); } + @TestMetadata("returnBoxedFromLambda.kt") + public void testReturnBoxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt"); + } + @TestMetadata("returnUnboxedDirect.kt") public void testReturnUnboxedDirect() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); } + @TestMetadata("returnUnboxedFromLambda.kt") + public void testReturnUnboxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt"); + } + @TestMetadata("returnUnboxedResume.kt") public void testReturnUnboxedResume() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java index 5f99520a06c..671102f9125 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java @@ -3990,11 +3990,21 @@ public class JsCodegenInlineTestGenerated extends AbstractJsCodegenInlineTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); } + @TestMetadata("returnBoxedFromLambda.kt") + public void testReturnBoxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt"); + } + @TestMetadata("returnUnboxedDirect.kt") public void testReturnUnboxedDirect() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); } + @TestMetadata("returnUnboxedFromLambda.kt") + public void testReturnUnboxedFromLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt"); + } + @TestMetadata("returnUnboxedResume.kt") public void testReturnUnboxedResume() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt");