From aef5911c7e4c667e684fd989fe0c8876317fb9c0 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 23 Aug 2017 15:30:20 +0300 Subject: [PATCH] Obtain original suspend function view for inline codegen It's necessary for generic inline suspend as a codegen for it uses binding slice SUSPEND_FUNCTION_TO_JVM_VIEW to generate fake continuation parameter, so all the descriptors that are used for body generation must be obtained from the SUSPEND_FUNCTION_TO_JVM_VIEW #KT-19528 Fixed --- .../kotlin/codegen/ExpressionCodegen.java | 5 ++- .../coroutines/coroutineCodegenUtil.kt | 7 ++++ .../box/coroutines/inlineFunInGenericClass.kt | 31 +++++++++++++++ .../inlineGenericFunCalledFromSubclass.kt | 39 +++++++++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 12 ++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 12 ++++++ .../LightAnalysisModeTestGenerated.java | 12 ++++++ .../semantics/JsCodegenBoxTestGenerated.java | 12 ++++++ 8 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/codegen/box/coroutines/inlineFunInGenericClass.kt create mode 100644 compiler/testData/codegen/box/coroutines/inlineGenericFunCalledFromSubclass.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 60b8472c6f2..852ff6c45e5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2352,7 +2352,10 @@ public class ExpressionCodegen extends KtVisitor impleme if (!isInline) return defaultCallGenerator; FunctionDescriptor original = - unwrapInitialSignatureDescriptor(DescriptorUtils.unwrapFakeOverride((FunctionDescriptor) descriptor.getOriginal())); + CoroutineCodegenUtilKt.getOriginalSuspendFunctionView( + unwrapInitialSignatureDescriptor(DescriptorUtils.unwrapFakeOverride((FunctionDescriptor) descriptor.getOriginal())), + bindingContext + ); if (isDefaultCompilation) { return new InlineCodegenForDefaultBody(original, this, state, new PsiSourceCompilerForInline(this, callElement)); } 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 b76503b2ef4..8e0b625251d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt @@ -291,6 +291,13 @@ fun createMethodNodeForSuspendCoroutineOrReturn( fun D.unwrapInitialDescriptorForSuspendFunction(): D = this.safeAs()?.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) as D ?: this + +fun FunctionDescriptor.getOriginalSuspendFunctionView(bindingContext: BindingContext): FunctionDescriptor = + if (isSuspend) + getOrCreateJvmSuspendFunctionView(unwrapInitialDescriptorForSuspendFunction().original, bindingContext) + else + this + fun InstructionAdapter.loadCoroutineSuspendedMarker() { invokestatic( COROUTINES_INTRINSICS_FILE_FACADE_INTERNAL_NAME.internalName, diff --git a/compiler/testData/codegen/box/coroutines/inlineFunInGenericClass.kt b/compiler/testData/codegen/box/coroutines/inlineFunInGenericClass.kt new file mode 100644 index 00000000000..4eee3b4e2ac --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/inlineFunInGenericClass.kt @@ -0,0 +1,31 @@ +// WITH_RUNTIME +// WITH_COROUTINES +import helpers.* +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +suspend fun suspendThere(v: Any?): String = suspendCoroutineOrReturn { x -> + x.resume(v?.toString() ?: "") + COROUTINE_SUSPENDED +} + + +class A(val arg: T) { + var result = "" + inline suspend fun foo() { + result = suspendThere(arg) + } +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + val a = A("OK") + builder { + a.foo() + } + + return a.result +} diff --git a/compiler/testData/codegen/box/coroutines/inlineGenericFunCalledFromSubclass.kt b/compiler/testData/codegen/box/coroutines/inlineGenericFunCalledFromSubclass.kt new file mode 100644 index 00000000000..e8ebf741eef --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/inlineGenericFunCalledFromSubclass.kt @@ -0,0 +1,39 @@ +// WITH_RUNTIME +// WITH_COROUTINES +// WITH_REFLECT +import helpers.* +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x -> + x.resume(v) + COROUTINE_SUSPENDED +} + +suspend fun foo(x: suspend () -> String): String = x() + +abstract class A { + inline suspend fun baz(): String { + return foo { + suspendThere(T::class.simpleName!!) + } + } + +} +class B : A() { + suspend fun bar(): String { + return baz() + } +} +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} +class OK +fun box(): String { + var result = "fail" + builder { + result = B().bar() + } + + return result +} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 90fb86e4001..2bf23ac34b5 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -5171,6 +5171,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("inlineFunInGenericClass.kt") + public void testInlineFunInGenericClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/inlineFunInGenericClass.kt"); + doTest(fileName); + } + + @TestMetadata("inlineGenericFunCalledFromSubclass.kt") + public void testInlineGenericFunCalledFromSubclass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/inlineGenericFunCalledFromSubclass.kt"); + doTest(fileName); + } + @TestMetadata("inlineSuspendFunction.kt") public void testInlineSuspendFunction() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/inlineSuspendFunction.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 473fb9a9504..24d534ae464 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -5171,6 +5171,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("inlineFunInGenericClass.kt") + public void testInlineFunInGenericClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/inlineFunInGenericClass.kt"); + doTest(fileName); + } + + @TestMetadata("inlineGenericFunCalledFromSubclass.kt") + public void testInlineGenericFunCalledFromSubclass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/inlineGenericFunCalledFromSubclass.kt"); + doTest(fileName); + } + @TestMetadata("inlineSuspendFunction.kt") public void testInlineSuspendFunction() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/inlineSuspendFunction.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index f14e00a52c4..ea17265db77 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -5171,6 +5171,18 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("inlineFunInGenericClass.kt") + public void testInlineFunInGenericClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/inlineFunInGenericClass.kt"); + doTest(fileName); + } + + @TestMetadata("inlineGenericFunCalledFromSubclass.kt") + public void testInlineGenericFunCalledFromSubclass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/inlineGenericFunCalledFromSubclass.kt"); + doTest(fileName); + } + @TestMetadata("inlineSuspendFunction.kt") public void testInlineSuspendFunction() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/inlineSuspendFunction.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 f2ced9d82ad..f6ddaee3d52 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 @@ -5879,6 +5879,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("inlineFunInGenericClass.kt") + public void testInlineFunInGenericClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/inlineFunInGenericClass.kt"); + doTest(fileName); + } + + @TestMetadata("inlineGenericFunCalledFromSubclass.kt") + public void testInlineGenericFunCalledFromSubclass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/inlineGenericFunCalledFromSubclass.kt"); + doTest(fileName); + } + @TestMetadata("inlineSuspendFunction.kt") public void testInlineSuspendFunction() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/inlineSuspendFunction.kt");