diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index 31a33ca3c8b..3b9858d4d64 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -589,4 +589,8 @@ public class ClosureCodegen extends MemberCodegen { MemberScope scope = functionClass.getDefaultType().getMemberScope(); return scope.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND).iterator().next(); } + + public boolean isCallableReference() { + return functionReferenceTarget != null; + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 8e60ed37c61..5eefd262d8b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2742,6 +2742,15 @@ public class ExpressionCodegen extends KtVisitor impleme addInlineMarker(v, false); } + // If a suspend function returns unboxed inline class, we should check for COROUTINE_SUSPENDED and only then box the inline class. + if (insideCallableReference() && resolvedCall.getResultingDescriptor() instanceof FunctionDescriptor) { + KotlinType unboxedInlineClass = CoroutineCodegenUtilKt.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass( + (FunctionDescriptor) resolvedCall.getResultingDescriptor(), typeMapper); + if (unboxedInlineClass != null) { + CoroutineCodegenUtilKt.generateCoroutineSuspendedCheck(v, state.getLanguageVersionSettings()); + } + } + KotlinType returnType = resolvedCall.getResultingDescriptor().getReturnType(); if (returnType != null && KotlinBuiltIns.isNothing(returnType)) { if (state.getUseKotlinNothingValueException()) { @@ -2756,8 +2765,7 @@ public class ExpressionCodegen extends KtVisitor impleme } private boolean insideCallableReference() { - return (parentCodegen instanceof ClosureCodegen) && - ((ClosureCodegen) parentCodegen).superClassAsmType.equals(FUNCTION_REFERENCE_IMPL); + return (parentCodegen instanceof ClosureCodegen) && ((ClosureCodegen) parentCodegen).isCallableReference(); } private void putReceiverAndInlineMarkerIfNeeded( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt index 5fde7c5dece..b05658e805f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt @@ -726,12 +726,7 @@ class CoroutineCodegenForNamedFunction private constructor( with(codegen.v) { // We need to box the returned inline class in resume path. // But first, check for COROUTINE_SUSPENDED, since the function can return it - dup() - loadCoroutineSuspendedMarker(languageVersionSettings) - val elseLabel = Label() - ifacmpne(elseLabel) - areturn(AsmTypes.OBJECT_TYPE) - mark(elseLabel) + generateCoroutineSuspendedCheck(languageVersionSettings) // Now we box the inline class StackValue.coerce(AsmTypes.OBJECT_TYPE, typeMapper.mapType(inlineClassToBoxInInvokeSuspend), this) StackValue.boxInlineClass(inlineClassToBoxInInvokeSuspend, this) 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 347ca12c99a..9c9b05f04c0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt @@ -490,6 +490,15 @@ fun InstructionAdapter.loadCoroutineSuspendedMarker(languageVersionSettings: Lan ) } +internal fun InstructionAdapter.generateCoroutineSuspendedCheck(languageVersionSettings: LanguageVersionSettings) { + dup() + loadCoroutineSuspendedMarker(languageVersionSettings) + val elseLabel = Label() + ifacmpne(elseLabel) + areturn(OBJECT_TYPE) + mark(elseLabel) +} + fun InstructionAdapter.invokeDoResumeWithUnit(thisName: String) { // .doResume(Unit, null) StackValue.putUnitInstance(this) 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 e9d8bffb92b..e6319ff933a 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 @@ -7441,6 +7441,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt"); } + @TestMetadata("boxReturnValueOfSuspendFunctionReferenceResume.kt") + public void testBoxReturnValueOfSuspendFunctionReferenceResume() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt"); + } + @TestMetadata("boxReturnValueOfSuspendLambda.kt") public void testBoxReturnValueOfSuspendLambda() throws Exception { runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt"); diff --git a/compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt b/compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt new file mode 100644 index 00000000000..e122d0725f7 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt @@ -0,0 +1,30 @@ +// IGNORE_BACKEND: JS_IR +// IGNORE_BACKEND: JS_IR_ES6 +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.* + +inline class R(val x: Any) + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +suspend fun call(fn: suspend () -> T) = fn() + +fun useR(r: R) = if (r.x == "OK") "OK" else "fail: $r" + +var c: Continuation? = null + +suspend fun ok() = suspendCoroutine { c = it } + +fun box(): String { + var res: String = "fail" + builder { + res = useR(call(::ok)) + } + c?.resume(R("OK")) + return res +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/coroutines/inlineClasses/returnResult.kt b/compiler/testData/codegen/box/coroutines/inlineClasses/returnResult.kt index 6f205127c2a..335784c6248 100644 --- a/compiler/testData/codegen/box/coroutines/inlineClasses/returnResult.kt +++ b/compiler/testData/codegen/box/coroutines/inlineClasses/returnResult.kt @@ -1,5 +1,6 @@ // WITH_RUNTIME // WITH_COROUTINES +// IGNORE_BACKEND: JVM_IR import helpers.* import kotlin.coroutines.* diff --git a/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_Any.kt b/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_Any.kt index 8652e00d255..2ccf399405e 100644 --- a/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_Any.kt +++ b/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_Any.kt @@ -23,4 +23,5 @@ suspend fun test() { // -- 1 in 'useICAny(suspendGeneric(ICAny(""))) // -- 1 in 'equals-impl' for ICAny -// 2 INVOKEVIRTUAL ICAny\.unbox-impl \ No newline at end of file +// -- 2 on resume path of suspendICAny +// 4 INVOKEVIRTUAL ICAny\.unbox-impl \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_InlineAny.kt b/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_InlineAny.kt index 5ae6d49bf84..c41d9c48729 100644 --- a/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_InlineAny.kt +++ b/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_InlineAny.kt @@ -11,14 +11,14 @@ fun useIC(x: IC1) {} fun useAny(x: Any) {} suspend fun test() { - useIC(suspendIC()) + useIC(suspendIC()) // IC1.unbox-impl of resume path useIC(suspendGeneric(IC1(IC0("")))) // IC1.box-impl, IC1.unbox-impl useAny(suspendAny()) - useAny(suspendIC()) // IC1.box-impl + useAny(suspendIC()) // IC1.box-impl, IC1.unbox-impl of resume path } // 0 INVOKESTATIC IC0\.box-impl // 3 INVOKESTATIC IC1\.box-impl // 1 INVOKEVIRTUAL IC0\.unbox-impl -// 2 INVOKEVIRTUAL IC1\.unbox-impl +// 4 INVOKEVIRTUAL IC1\.unbox-impl diff --git a/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_String.kt b/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_String.kt index af083646c90..f5d15e1f5ac 100644 --- a/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_String.kt +++ b/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_String.kt @@ -23,4 +23,5 @@ suspend fun test() { // -- 1 in 'useICString(suspendGeneric(ICString(""))) // -- 1 in 'equals-impl' for ICString -// 2 INVOKEVIRTUAL ICString\.unbox-impl \ No newline at end of file +// -- 2 in resume path of suspendICString +// 4 INVOKEVIRTUAL ICString\.unbox-impl \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/returnResult.kt b/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/returnResult.kt index 03001bc61be..65e6cd67250 100644 --- a/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/returnResult.kt +++ b/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/returnResult.kt @@ -7,5 +7,5 @@ inline class OurAny(val a: Any) suspend fun returnsUnboxed(): OurAny = OurAny("OK") -// 1 INVOKESTATIC kotlin/Result.box-impl +// 0 INVOKESTATIC kotlin/Result.box-impl // 0 INVOKESTATIC OurAny.box-impl \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 7d5bf767743..022ec0b0483 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -8151,6 +8151,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt"); } + @TestMetadata("boxReturnValueOfSuspendFunctionReferenceResume.kt") + public void testBoxReturnValueOfSuspendFunctionReferenceResume() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt"); + } + @TestMetadata("boxReturnValueOfSuspendLambda.kt") public void testBoxReturnValueOfSuspendLambda() throws Exception { runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 46fc6f0f74d..87cb15c1eca 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -8151,6 +8151,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt"); } + @TestMetadata("boxReturnValueOfSuspendFunctionReferenceResume.kt") + public void testBoxReturnValueOfSuspendFunctionReferenceResume() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt"); + } + @TestMetadata("boxReturnValueOfSuspendLambda.kt") public void testBoxReturnValueOfSuspendLambda() throws Exception { runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 9cf466343ac..9a87e4980eb 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -7441,6 +7441,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt"); } + @TestMetadata("boxReturnValueOfSuspendFunctionReferenceResume.kt") + public void testBoxReturnValueOfSuspendFunctionReferenceResume() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt"); + } + @TestMetadata("boxReturnValueOfSuspendLambda.kt") public void testBoxReturnValueOfSuspendLambda() throws Exception { runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt"); 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 3c68a8727f3..8616c9bc2cd 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 @@ -6261,6 +6261,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt"); } + @TestMetadata("boxReturnValueOfSuspendFunctionReferenceResume.kt") + public void testBoxReturnValueOfSuspendFunctionReferenceResume() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt"); + } + @TestMetadata("boxReturnValueOfSuspendLambda.kt") public void testBoxReturnValueOfSuspendLambda() throws Exception { runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt"); 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 323af659743..415621b5e31 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 @@ -6261,6 +6261,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt"); } + @TestMetadata("boxReturnValueOfSuspendFunctionReferenceResume.kt") + public void testBoxReturnValueOfSuspendFunctionReferenceResume() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt"); + } + @TestMetadata("boxReturnValueOfSuspendLambda.kt") public void testBoxReturnValueOfSuspendLambda() throws Exception { runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt"); 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 969e950b442..3c1eed05c39 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 @@ -6261,6 +6261,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReference.kt"); } + @TestMetadata("boxReturnValueOfSuspendFunctionReferenceResume.kt") + public void testBoxReturnValueOfSuspendFunctionReferenceResume() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendFunctionReferenceResume.kt"); + } + @TestMetadata("boxReturnValueOfSuspendLambda.kt") public void testBoxReturnValueOfSuspendLambda() throws Exception { runTest("compiler/testData/codegen/box/coroutines/inlineClasses/boxReturnValueOfSuspendLambda.kt");