From d97fa604e11940db8cd0e70eedfadf702de6327f Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 29 Jun 2017 21:07:04 +0300 Subject: [PATCH] Write metadata for suspend function into anonymous coroutine classes To render nice Kotlin types in toString() of continuation --- .../kotlin/codegen/ClosureCodegen.java | 2 +- .../codegen/coroutines/CoroutineCodegen.kt | 8 +++-- .../box/coroutines/coroutineToString.kt | 33 +++++++++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 6 ++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++++ .../LightAnalysisModeTestGenerated.java | 6 ++++ 6 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/codegen/box/coroutines/coroutineToString.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index d1d7fbf3d44..076271ae105 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -250,7 +250,7 @@ public class ClosureCodegen extends MemberCodegen { * This is needed because once we're serializing this to a proto, there's no place to store information about external type parameters. */ @NotNull - private static FunctionDescriptor createFreeLambdaDescriptor(@NotNull FunctionDescriptor descriptor) { + public static FunctionDescriptor createFreeLambdaDescriptor(@NotNull FunctionDescriptor descriptor) { FunctionDescriptor.CopyBuilder builder = descriptor.newCopyBuilder(); List typeParameters = new ArrayList<>(0); builder.setTypeParameters(typeParameters); 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 646fb74ed3e..05169b8e7df 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.context.ClosureContext import org.jetbrains.kotlin.codegen.context.MethodContext +import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension import org.jetbrains.kotlin.coroutines.isSuspendLambda import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations @@ -39,6 +40,7 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.serialization.DescriptorSerializer import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -475,8 +477,10 @@ class CoroutineCodegenForNamedFunction private constructor( } override fun generateKotlinMetadataAnnotation() { - writeKotlinMetadata(v, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, 0) { - // Do not write method metadata for raw coroutine state machines + writeKotlinMetadata(v, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, 0) { av -> + val serializer = DescriptorSerializer.createForLambda(JvmSerializerExtension(v.serializationBindings, state)) + val functionProto = serializer.functionProto(createFreeLambdaDescriptor(suspendFunctionJvmView)).build() + AsmUtil.writeAnnotationData(av, serializer, functionProto) } } diff --git a/compiler/testData/codegen/box/coroutines/coroutineToString.kt b/compiler/testData/codegen/box/coroutines/coroutineToString.kt new file mode 100644 index 00000000000..fd02bebdc86 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/coroutineToString.kt @@ -0,0 +1,33 @@ +// TARGET_BACKEND: JVM +// WITH_REFLECT +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +class A { + suspend fun foo() {} + + suspend fun bar(): T { + foo() + return suspendCoroutineOrReturn { x -> + x.resume(x.toString() as T) + COROUTINE_SUSPENDED + } + } +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var result = "" + + builder { + result = A().bar() + } + + return if (result == "(kotlin.coroutines.experimental.Continuation) -> kotlin.Any?") "OK" else "Fail: $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 755d276cf64..30f1c4eb4e2 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 @@ -5018,6 +5018,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("coroutineToString.kt") + public void testCoroutineToString() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/coroutineToString.kt"); + doTest(fileName); + } + @TestMetadata("createCoroutineSafe.kt") public void testCreateCoroutineSafe() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/createCoroutineSafe.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 0d2105dcda8..61690be8606 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -5018,6 +5018,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("coroutineToString.kt") + public void testCoroutineToString() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/coroutineToString.kt"); + doTest(fileName); + } + @TestMetadata("createCoroutineSafe.kt") public void testCreateCoroutineSafe() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/createCoroutineSafe.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 8a561b96284..36a274cf08d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -5018,6 +5018,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("coroutineToString.kt") + public void testCoroutineToString() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/coroutineToString.kt"); + doTest(fileName); + } + @TestMetadata("createCoroutineSafe.kt") public void testCreateCoroutineSafe() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/createCoroutineSafe.kt");