From 2d88419c380e32116ba1cb3c5b944463b36b6dbb Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 3 Feb 2017 16:44:16 +0300 Subject: [PATCH] Fix annotation deserialization on suspend functions Use proper initial/frontend version of suspend descriptor when writing METHOD_FOR_FUNCTION, because serializer uses this version Also this commit contains adjustments of neighboring code to the describe change #KT-16093 Fixed --- .../jetbrains/kotlin/codegen/ClosureCodegen.java | 10 ++++------ .../jetbrains/kotlin/codegen/FunctionCodegen.java | 6 +++++- .../org/jetbrains/kotlin/codegen/codegenUtil.kt | 4 +++- .../kotlin/codegen/coroutines/CoroutineCodegen.kt | 2 ++ .../suspendCoroutineUnavailableWithNewAPI.kt | 14 ++++++++++++++ .../suspendCoroutineUnavailableWithOldAPI.kt | 14 ++++++++++++++ .../coroutines/annotatedSuspendFun.kt | 5 +++++ .../coroutines/annotatedSuspendFun.txt | 9 +++++++++ .../DiagnosticsTestWithStdLibGenerated.java | 12 ++++++++++++ .../jvm/compiler/LoadJavaTestGenerated.java | 15 +++++++++++++++ 10 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendCoroutineUnavailableWithNewAPI.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendCoroutineUnavailableWithOldAPI.kt create mode 100644 compiler/testData/loadJava/compiledKotlinWithStdlib/coroutines/annotatedSuspendFun.kt create mode 100644 compiler/testData/loadJava/compiledKotlinWithStdlib/coroutines/annotatedSuspendFun.txt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index eb847ddccb8..c1e37aa78a8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -35,13 +35,11 @@ import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.descriptors.*; -import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor; import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl; import org.jetbrains.kotlin.incremental.components.NoLookupLocation; import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader; import org.jetbrains.kotlin.psi.KtElement; -import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; @@ -64,7 +62,6 @@ import java.util.List; import static org.jetbrains.kotlin.codegen.AsmUtil.*; import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConst; import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLOSURE; -import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass; import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHOD_FOR_FUNCTION; import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*; import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; @@ -233,9 +230,10 @@ public class ClosureCodegen extends MemberCodegen { @Override protected void generateKotlinMetadataAnnotation() { - FunctionDescriptor freeLambdaDescriptor = createFreeLambdaDescriptor(funDescriptor); - Method method = v.getSerializationBindings().get(METHOD_FOR_FUNCTION, funDescriptor); - assert method != null : "No method for " + funDescriptor; + FunctionDescriptor frontendFunDescriptor = CodegenUtilKt.unwrapFrontendVersion(funDescriptor); + FunctionDescriptor freeLambdaDescriptor = createFreeLambdaDescriptor(frontendFunDescriptor); + Method method = v.getSerializationBindings().get(METHOD_FOR_FUNCTION, frontendFunDescriptor); + assert method != null : "No method for " + frontendFunDescriptor; v.getSerializationBindings().put(METHOD_FOR_FUNCTION, freeLambdaDescriptor, method); final DescriptorSerializer serializer = diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index df741c4fb76..e9b9f035721 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -209,7 +209,11 @@ public class FunctionCodegen { getThrownExceptions(functionDescriptor, typeMapper)); if (CodegenContextUtil.isImplClassOwner(owner)) { - v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod); + v.getSerializationBindings().put( + METHOD_FOR_FUNCTION, + CodegenUtilKt.unwrapFrontendVersion(functionDescriptor), + asmMethod + ); } generateMethodAnnotations(functionDescriptor, asmMethod, mv); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt index ea5a1347c82..d8f0712fc68 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt @@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.codegen.context.FieldOwnerContext import org.jetbrains.kotlin.codegen.context.PackageContext +import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter import org.jetbrains.kotlin.codegen.state.GenerationState @@ -53,7 +54,6 @@ import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.checker.KotlinTypeChecker -import org.jetbrains.kotlin.types.isFlexible import org.jetbrains.kotlin.utils.DFS import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import org.jetbrains.org.objectweb.asm.Label @@ -375,3 +375,5 @@ fun initializeVariablesForDestructuredLambdaParameters(codegen: ExpressionCodege codegen.isShouldMarkLineNumbers = savedIsShouldMarkLineNumbers } + +fun D.unwrapFrontendVersion() = unwrapInitialDescriptorForSuspendFunction() 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 26a03c0fe6a..ca4ebd7b5ad 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt @@ -108,6 +108,8 @@ class CoroutineCodegen private constructor( setReturnType( funDescriptor.module.getContinuationOfTypeOrAny(builtIns.unitType) ) + // 'create' method should not inherit initial descriptor for suspend function from original descriptor + putUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION, null) setVisibility(Visibilities.PUBLIC) } diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendCoroutineUnavailableWithNewAPI.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendCoroutineUnavailableWithNewAPI.kt new file mode 100644 index 00000000000..19eb41c7542 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendCoroutineUnavailableWithNewAPI.kt @@ -0,0 +1,14 @@ +// !API_VERSION: 1.1 +// SKIP_TXT + +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +suspend fun foo(): Unit = suspendCoroutine { + it.resume(Unit) +} + +suspend fun bar(): Unit = suspendCoroutineOrReturn { + it.resume(Unit) + COROUTINE_SUSPENDED +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendCoroutineUnavailableWithOldAPI.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendCoroutineUnavailableWithOldAPI.kt new file mode 100644 index 00000000000..29265db81f0 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendCoroutineUnavailableWithOldAPI.kt @@ -0,0 +1,14 @@ +// !API_VERSION: 1.0 +// SKIP_TXT + +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +suspend fun foo(): Unit = suspendCoroutine { + it.resume(Unit) +} + +suspend fun bar(): Unit = suspendCoroutineOrReturn { + it.resume(Unit) + COROUTINE_SUSPENDED +} diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/coroutines/annotatedSuspendFun.kt b/compiler/testData/loadJava/compiledKotlinWithStdlib/coroutines/annotatedSuspendFun.kt new file mode 100644 index 00000000000..8459c2e40db --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/coroutines/annotatedSuspendFun.kt @@ -0,0 +1,5 @@ +//ALLOW_AST_ACCESS +package test + +annotation class Anno(val t: String) +@Anno("foo") suspend fun foo() {} diff --git a/compiler/testData/loadJava/compiledKotlinWithStdlib/coroutines/annotatedSuspendFun.txt b/compiler/testData/loadJava/compiledKotlinWithStdlib/coroutines/annotatedSuspendFun.txt new file mode 100644 index 00000000000..751eb70db4f --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlinWithStdlib/coroutines/annotatedSuspendFun.txt @@ -0,0 +1,9 @@ +package test + +@test.Anno(t = "foo") public suspend fun foo(): kotlin.Unit + +public final annotation class Anno : kotlin.Annotation { + /*primary*/ public constructor Anno(/*0*/ t: kotlin.String) + public final val t: kotlin.String + public final fun (): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index bbdbc4bd03c..13d898f55e1 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -791,6 +791,18 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW doTest(fileName); } + @TestMetadata("suspendCoroutineUnavailableWithNewAPI.kt") + public void testSuspendCoroutineUnavailableWithNewAPI() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendCoroutineUnavailableWithNewAPI.kt"); + doTest(fileName); + } + + @TestMetadata("suspendCoroutineUnavailableWithOldAPI.kt") + public void testSuspendCoroutineUnavailableWithOldAPI() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendCoroutineUnavailableWithOldAPI.kt"); + doTest(fileName); + } + @TestMetadata("suspendDestructuring.kt") public void testSuspendDestructuring() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendDestructuring.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java index 739689fab82..2e638538506 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java @@ -4944,6 +4944,21 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { } } + @TestMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/coroutines") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Coroutines extends AbstractLoadJavaTest { + public void testAllFilesPresentInCoroutines() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlinWithStdlib/coroutines"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("annotatedSuspendFun.kt") + public void testAnnotatedSuspendFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/coroutines/annotatedSuspendFun.kt"); + doTestCompiledKotlinWithStdlib(fileName); + } + } + @TestMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/mutability") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)