From 70a4ed3ebc825ad32534dd34f361ae706a6aa5cc Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Fri, 16 Oct 2020 01:50:30 +0200 Subject: [PATCH] Box inline class returned from suspend lambda non-locally All inline classes should be boxed coming in and out of lambdas, however, if the inline class was returned non-locally, it was not boxed. This change fixes the issue in Old JVM BE. #KT-41194 In progress --- .../kotlin/codegen/ExpressionCodegen.java | 14 ++++++--- .../coroutines/coroutineCodegenUtil.kt | 9 ++++++ .../ir/FirBlackBoxCodegenTestGenerated.java | 5 +++ .../inlineClasses/nonLocalReturn.kt | 31 +++++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 5 +++ .../LightAnalysisModeTestGenerated.java | 5 +++ .../ir/IrBlackBoxCodegenTestGenerated.java | 5 +++ .../IrJsCodegenBoxES6TestGenerated.java | 5 +++ .../IrJsCodegenBoxTestGenerated.java | 5 +++ .../semantics/JsCodegenBoxTestGenerated.java | 5 +++ 10 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/codegen/box/coroutines/inlineClasses/nonLocalReturn.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 287ea8e5b9e..b9ffc34b607 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -1708,17 +1708,23 @@ public class ExpressionCodegen extends KtVisitor impleme // This is inline lambda. Find inline-site and check, whether it is suspend functions returning unboxed inline class CodegenContext inlineSiteContext = this.context.getFirstCrossInlineOrNonInlineContext(); KotlinType originalInlineClass = null; + boolean invokeSuspendOfLambda = false; + FunctionDescriptor inlineSiteDescriptor = null; if (inlineSiteContext instanceof MethodContext) { - originalInlineClass = CoroutineCodegenUtilKt - .originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass( - ((MethodContext) inlineSiteContext).getFunctionDescriptor(), typeMapper); + inlineSiteDescriptor = ((MethodContext) inlineSiteContext).getFunctionDescriptor(); + originalInlineClass = CoroutineCodegenUtilKt + .originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass(inlineSiteDescriptor, typeMapper); + invokeSuspendOfLambda = CoroutineCodegenUtilKt.isInvokeSuspendOfLambda(inlineSiteDescriptor); } if (originalInlineClass != null) { returnType = typeMapper.mapType(originalInlineClass); returnKotlinType = originalInlineClass; - } else { + } else if (!invokeSuspendOfLambda) { returnType = nonLocalReturn.returnType.getType(); returnKotlinType = nonLocalReturn.returnType.getKotlinType(); + } else { + returnType = OBJECT_TYPE; + returnKotlinType = inlineSiteDescriptor.getReturnType(); } } else { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt index 9844ec0b739..98ad453c493 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt @@ -543,3 +543,12 @@ val EXPERIMENTAL_CONTINUATION_ASM_TYPE = StandardNames.CONTINUATION_INTERFACE_FQ @JvmField val RELEASE_CONTINUATION_ASM_TYPE = StandardNames.CONTINUATION_INTERFACE_FQ_NAME_RELEASE.topLevelClassAsmType() + +fun FunctionDescriptor.isInvokeSuspendOfLambda(): Boolean { + if (this !is SimpleFunctionDescriptor) return false + if (valueParameters.size != 1 || + valueParameters[0].name.asString() != SUSPEND_CALL_RESULT_NAME || + name.asString() != "invokeSuspend" + ) return false + return containingDeclaration is SyntheticClassDescriptorForLambda +} \ No newline at end of file diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index b9228686331..8fe8d29ca9d 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -7577,6 +7577,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @TestMetadata("nonLocalReturn.kt") + public void testNonLocalReturn() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/inlineClasses/nonLocalReturn.kt"); + } + @TestMetadata("compiler/testData/codegen/box/coroutines/inlineClasses/direct") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/testData/codegen/box/coroutines/inlineClasses/nonLocalReturn.kt b/compiler/testData/codegen/box/coroutines/inlineClasses/nonLocalReturn.kt new file mode 100644 index 00000000000..6e2915ca13b --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/inlineClasses/nonLocalReturn.kt @@ -0,0 +1,31 @@ +// WITH_RUNTIME +// IGNORE_BACKEND: JVM_IR, JS_IR +// IGNORE_BACKEND_FIR: JVM_IR + +import kotlin.coroutines.* + +fun builder(c: suspend () -> T): T { + var res: T? = null + c.startCoroutine(Continuation(EmptyCoroutineContext) { + res = it.getOrThrow() + }) + return res!! +} + +suspend fun runSuspend(c: suspend () -> T): T { + return c() +} + +@Suppress("RESULT_CLASS_IN_RETURN_TYPE") +suspend fun foo(): Result = runSuspend { + run { return@runSuspend Result.failure(RuntimeException("OK")) } +} + +fun box(): String { + return try { + builder { foo() }.getOrThrow() + "FAIL" + } catch (e: RuntimeException) { + e.message!! + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 6e4acaa3720..28bf29bac73 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -8292,6 +8292,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @TestMetadata("nonLocalReturn.kt") + public void testNonLocalReturn() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/inlineClasses/nonLocalReturn.kt"); + } + @TestMetadata("compiler/testData/codegen/box/coroutines/inlineClasses/direct") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index f7a031c6507..e6e874cd39e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -8292,6 +8292,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @TestMetadata("nonLocalReturn.kt") + public void testNonLocalReturn() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/inlineClasses/nonLocalReturn.kt"); + } + @TestMetadata("compiler/testData/codegen/box/coroutines/inlineClasses/direct") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 98786843d79..35d06df29e7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -7577,6 +7577,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @TestMetadata("nonLocalReturn.kt") + public void testNonLocalReturn() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/inlineClasses/nonLocalReturn.kt"); + } + @TestMetadata("compiler/testData/codegen/box/coroutines/inlineClasses/direct") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index a9589e3e3a9..61381efb420 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -6332,6 +6332,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true); } + @TestMetadata("nonLocalReturn.kt") + public void testNonLocalReturn() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/inlineClasses/nonLocalReturn.kt"); + } + @TestMetadata("compiler/testData/codegen/box/coroutines/inlineClasses/direct") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 80e9e9312f2..0e6ed5f424b 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -6332,6 +6332,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); } + @TestMetadata("nonLocalReturn.kt") + public void testNonLocalReturn() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/inlineClasses/nonLocalReturn.kt"); + } + @TestMetadata("compiler/testData/codegen/box/coroutines/inlineClasses/direct") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 78092b5c8e0..309b144e2a5 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -6332,6 +6332,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/coroutines/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); } + @TestMetadata("nonLocalReturn.kt") + public void testNonLocalReturn() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/inlineClasses/nonLocalReturn.kt"); + } + @TestMetadata("compiler/testData/codegen/box/coroutines/inlineClasses/direct") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)