diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt index 8171dec82e9..4d71709da61 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt @@ -602,11 +602,12 @@ class CoroutineTransformerMethodVisitor( } private fun dropUnboxInlineClassMarkers(methodNode: MethodNode, suspensionPoints: List) { - for (marker in methodNode.instructions.asSequence() - .filter { isBeforeUnboxInlineClassMarker(it) || isAfterUnboxInlineClassMarker(it) }.toList() - ) { + for (marker in methodNode.instructions.asSequence().filter { isBeforeUnboxInlineClassMarker(it) }.toList()) { methodNode.instructions.removeAll(listOf(marker.previous, marker)) } + for (marker in methodNode.instructions.asSequence().filter { isAfterUnboxInlineClassMarker(it) }.toList()) { + methodNode.instructions.removeAll(listOf(marker.previous.previous, marker.previous, marker)) + } for (suspension in suspensionPoints) { methodNode.instructions.removeAll(suspension.unboxInlineClassInstructions) } @@ -1142,7 +1143,7 @@ internal class SuspensionPoint( if (!isBeforeUnboxInlineClassMarker(beforeMarker)) return emptyList() val afterMarker = beforeMarker.findNextOrNull { isAfterUnboxInlineClassMarker(it) } ?: error("Before unbox inline class marker without after unbox inline class marker") - return InsnSequence(beforeMarker.next, afterMarker.previous).toList() + return InsnSequence(beforeMarker.next, afterMarker.previous.previous).toList() } operator fun contains(insn: AbstractInsnNode): Boolean { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt index 751fc28e1fe..681e162a8cc 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt @@ -416,6 +416,11 @@ internal fun addUnboxInlineClassMarkersIfNeeded(v: InstructionAdapter, descripto if (inlineClass != null) { addBeforeUnboxInlineClassMarker(v) StackValue.unboxInlineClass(AsmTypes.OBJECT_TYPE, inlineClass, v) + // Suspend functions always returns Any?, but the unboxing disrupts type analysis of the bytecode. + // For example, if the underlying type is String, CHECKCAST String is removed. + // However, the unboxing is moved to the resume path, the direct path still has Any?, but now, without the CHECKCAST. + // Thus, we add CHECKCAST Object, which we remove, after we copy the unboxing to the resume path. + v.checkcast(AsmTypes.OBJECT_TYPE) addAfterUnboxInlineClassMarker(v) } } diff --git a/compiler/testData/codegen/box/coroutines/inlineClasses/direct/covariantOverrideSuspendFunSameJvmType.kt b/compiler/testData/codegen/box/coroutines/inlineClasses/direct/covariantOverrideSuspendFunSameJvmType.kt index 5ee93e52c59..9bc0b0e1873 100644 --- a/compiler/testData/codegen/box/coroutines/inlineClasses/direct/covariantOverrideSuspendFunSameJvmType.kt +++ b/compiler/testData/codegen/box/coroutines/inlineClasses/direct/covariantOverrideSuspendFunSameJvmType.kt @@ -1,6 +1,5 @@ // WITH_RUNTIME // WITH_COROUTINES -// IGNORE_BACKEND_FIR: JVM_IR import helpers.* import kotlin.coroutines.* diff --git a/compiler/testData/codegen/box/coroutines/inlineClasses/resume/covariantOverrideSuspendFunSameJvmType.kt b/compiler/testData/codegen/box/coroutines/inlineClasses/resume/covariantOverrideSuspendFunSameJvmType.kt index 2288cf86b8b..b24b2f7fa91 100644 --- a/compiler/testData/codegen/box/coroutines/inlineClasses/resume/covariantOverrideSuspendFunSameJvmType.kt +++ b/compiler/testData/codegen/box/coroutines/inlineClasses/resume/covariantOverrideSuspendFunSameJvmType.kt @@ -1,6 +1,6 @@ // WITH_RUNTIME // WITH_COROUTINES -// IGNORE_BACKEND_FIR: JVM_IR +// IGNORE_BACKEND: JS_IR import helpers.* import kotlin.coroutines.* diff --git a/compiler/testData/codegen/box/coroutines/inlineClasses/resume/covariantOverrideSuspendFunWithNullableInlineClassSameJvmType.kt b/compiler/testData/codegen/box/coroutines/inlineClasses/resume/covariantOverrideSuspendFunWithNullableInlineClassSameJvmType.kt index 2d901489cd4..44553622e0b 100644 --- a/compiler/testData/codegen/box/coroutines/inlineClasses/resume/covariantOverrideSuspendFunWithNullableInlineClassSameJvmType.kt +++ b/compiler/testData/codegen/box/coroutines/inlineClasses/resume/covariantOverrideSuspendFunWithNullableInlineClassSameJvmType.kt @@ -1,5 +1,6 @@ // WITH_RUNTIME // WITH_COROUTINES +// IGNORE_BACKEND: JS_IR import helpers.* import kotlin.coroutines.* diff --git a/compiler/testData/codegen/box/coroutines/inlineClasses/resumeWithException/covariantOverrideSuspendFunSameJvmType.kt b/compiler/testData/codegen/box/coroutines/inlineClasses/resumeWithException/covariantOverrideSuspendFunSameJvmType.kt index 496c3519700..985147a4c0c 100644 --- a/compiler/testData/codegen/box/coroutines/inlineClasses/resumeWithException/covariantOverrideSuspendFunSameJvmType.kt +++ b/compiler/testData/codegen/box/coroutines/inlineClasses/resumeWithException/covariantOverrideSuspendFunSameJvmType.kt @@ -1,6 +1,6 @@ // WITH_RUNTIME // WITH_COROUTINES -// IGNORE_BACKEND_FIR: JVM_IR +// IGNORE_BACKEND: JS_IR import helpers.* import kotlin.coroutines.* diff --git a/compiler/testData/codegen/box/coroutines/inlineClasses/resumeWithException/covariantOverrideSuspendFunWithNullableInlineClassSameJvmType.kt b/compiler/testData/codegen/box/coroutines/inlineClasses/resumeWithException/covariantOverrideSuspendFunWithNullableInlineClassSameJvmType.kt index 48f400d924b..6f8ad7f75b5 100644 --- a/compiler/testData/codegen/box/coroutines/inlineClasses/resumeWithException/covariantOverrideSuspendFunWithNullableInlineClassSameJvmType.kt +++ b/compiler/testData/codegen/box/coroutines/inlineClasses/resumeWithException/covariantOverrideSuspendFunWithNullableInlineClassSameJvmType.kt @@ -1,5 +1,6 @@ // WITH_RUNTIME // WITH_COROUTINES +// IGNORE_BACKEND: JS_IR import helpers.* import kotlin.coroutines.* diff --git a/compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt b/compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt new file mode 100644 index 00000000000..7db31a06bbe --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt @@ -0,0 +1,30 @@ +// WITH_RUNTIME +// WITH_COROUTINES + +// FILE: inline.kt + +inline class IC(val s: String) + +suspend fun o(): IC = IC("O") +suspend fun k(): IC = IC("K") + +inline suspend fun inlineMe(): String { + return o().s + k().s +} + +// FILE: box.kt + +import helpers.* +import kotlin.coroutines.* + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res = "FAIL" + builder { + res = inlineMe() + } + return res +} diff --git a/compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt b/compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt new file mode 100644 index 00000000000..a78ed0301c8 --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt @@ -0,0 +1,41 @@ +// WITH_RUNTIME +// WITH_COROUTINES +// CHECK_STATE_MACHINE + +// FILE: inline.kt + +import helpers.* + +inline class IC(val s: String) + +suspend fun o(): IC { + StateMachineChecker.suspendHere() + return IC("O") +} + +suspend fun k(): IC { + StateMachineChecker.suspendHere() + return IC("K") +} + +inline suspend fun inlineMe(): String { + return o().s + k().s +} + +// FILE: box.kt + +import helpers.* +import kotlin.coroutines.* + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(CheckStateMachineContinuation) +} + +fun box(): String { + var res = "FAIL" + builder { + res = inlineMe() + } + StateMachineChecker.check(2) + return res +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index 392f7c0038e..ff91b91b751 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -4133,6 +4133,29 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo } } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineClass") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineClass extends AbstractBlackBoxInlineCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInInlineClass() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @TestMetadata("returnUnboxedDirect.kt") + public void testReturnUnboxedDirect() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); + } + + @TestMetadata("returnUnboxedResume.kt") + public void testReturnUnboxedResume() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt"); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index b5d818f3f8a..fcab45b07eb 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -4133,6 +4133,29 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi } } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineClass") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineClass extends AbstractCompileKotlinAgainstInlineKotlinTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTestWithCustomIgnoreDirective(this::doTest, TargetBackend.JVM, testDataFilePath, "// IGNORE_BACKEND_MULTI_MODULE: "); + } + + public void testAllFilesPresentInInlineClass() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @TestMetadata("returnUnboxedDirect.kt") + public void testReturnUnboxedDirect() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); + } + + @TestMetadata("returnUnboxedResume.kt") + public void testReturnUnboxedResume() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt"); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java index ffa99b5edc9..45a0a700a51 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java @@ -4008,6 +4008,29 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli } } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineClass") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineClass extends AbstractIrBlackBoxInlineCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); + } + + public void testAllFilesPresentInInlineClass() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @TestMetadata("returnUnboxedDirect.kt") + public void testReturnUnboxedDirect() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); + } + + @TestMetadata("returnUnboxedResume.kt") + public void testReturnUnboxedResume() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt"); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java index 10e2ecdaa2d..6d387a98518 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java @@ -4008,6 +4008,29 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC } } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineClass") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineClass extends AbstractIrCompileKotlinAgainstInlineKotlinTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTestWithCustomIgnoreDirective(this::doTest, TargetBackend.JVM_IR, testDataFilePath, "// IGNORE_BACKEND_MULTI_MODULE: "); + } + + public void testAllFilesPresentInInlineClass() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @TestMetadata("returnUnboxedDirect.kt") + public void testReturnUnboxedDirect() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); + } + + @TestMetadata("returnUnboxedResume.kt") + public void testReturnUnboxedResume() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt"); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java index 67d9f371657..70f62d5d9f0 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java @@ -3568,6 +3568,29 @@ public class IrJsCodegenInlineES6TestGenerated extends AbstractIrJsCodegenInline } } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineClass") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineClass extends AbstractIrJsCodegenInlineES6Test { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR_ES6, testDataFilePath); + } + + public void testAllFilesPresentInInlineClass() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true); + } + + @TestMetadata("returnUnboxedDirect.kt") + public void testReturnUnboxedDirect() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); + } + + @TestMetadata("returnUnboxedResume.kt") + public void testReturnUnboxedResume() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt"); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java index c4f6e3f6a17..53ce9862ff1 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java @@ -3568,6 +3568,29 @@ public class IrJsCodegenInlineTestGenerated extends AbstractIrJsCodegenInlineTes } } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineClass") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineClass extends AbstractIrJsCodegenInlineTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath); + } + + public void testAllFilesPresentInInlineClass() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); + } + + @TestMetadata("returnUnboxedDirect.kt") + public void testReturnUnboxedDirect() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); + } + + @TestMetadata("returnUnboxedResume.kt") + public void testReturnUnboxedResume() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt"); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java index 66a613e6843..4807256df14 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java @@ -3568,6 +3568,29 @@ public class JsCodegenInlineTestGenerated extends AbstractJsCodegenInlineTest { } } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineClass") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineClass extends AbstractJsCodegenInlineTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath); + } + + public void testAllFilesPresentInInlineClass() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); + } + + @TestMetadata("returnUnboxedDirect.kt") + public void testReturnUnboxedDirect() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt"); + } + + @TestMetadata("returnUnboxedResume.kt") + public void testReturnUnboxedResume() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt"); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)