From 7771e5914d702c6229a664d1926d82f29c84eb34 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 21 Dec 2021 20:06:07 +0100 Subject: [PATCH] Revert "Do not write version requirements for suspend functions" This reverts commit 6807ed66420d9456484bf04a7e161b093ce0c1a3. The reason is that Kotlin compilers until and including version 1.6.10 have code that detects obsolete coroutines via these version requirements (see `versionAndReleaseCoroutinesMismatch`). Since Kotlin 1.6.10 can read metadata of version 1.7, the earliest we can drop these version requirements is Kotlin 1.8.0. --- .../serialization/DescriptorSerializer.kt | 22 +++++++++++++++++++ .../versionRequirement/nestedClassMembers.kt | 2 ++ .../testData/versionRequirement/suspendFun.kt | 16 ++++++++++++++ .../AbstractVersionRequirementTest.kt | 18 +++++++++++++++ .../tools/kotlinp/testData/SimpleClass.txt | 1 + .../tools/kotlinp/testData/ValueClass.txt | 2 ++ 6 files changed, 61 insertions(+) create mode 100644 compiler/testData/versionRequirement/suspendFun.kt diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt index 7fabc07f5c5..6bb22bfd09d 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.serialization import com.intellij.openapi.project.Project import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.isSuspendFunctionType +import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype import org.jetbrains.kotlin.builtins.transformSuspendFunctionToRuntimeFunctionType import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.* @@ -330,6 +331,10 @@ class DescriptorSerializer private constructor( versionRequirementTable?.run { builder.addAllVersionRequirement(serializeVersionRequirements(descriptor)) + if (descriptor.isSuspendOrHasSuspendTypesInSignature()) { + builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion()) + } + if (descriptor.hasInlineClassTypesInSignature()) { builder.addVersionRequirement(writeVersionRequirement(LanguageFeature.InlineClasses)) } @@ -424,6 +429,10 @@ class DescriptorSerializer private constructor( versionRequirementTable?.run { builder.addAllVersionRequirement(serializeVersionRequirements(descriptor)) + if (descriptor.isSuspendOrHasSuspendTypesInSignature()) { + builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion()) + } + if (descriptor.hasInlineClassTypesInSignature()) { builder.addVersionRequirement(writeVersionRequirement(LanguageFeature.InlineClasses)) } @@ -464,6 +473,10 @@ class DescriptorSerializer private constructor( versionRequirementTable?.run { builder.addAllVersionRequirement(serializeVersionRequirements(descriptor)) + if (descriptor.isSuspendOrHasSuspendTypesInSignature()) { + builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion()) + } + if (descriptor.hasInlineClassTypesInSignature()) { builder.addVersionRequirement(writeVersionRequirement(LanguageFeature.InlineClasses)) } @@ -478,6 +491,15 @@ class DescriptorSerializer private constructor( return builder } + private fun MutableVersionRequirementTable.writeVersionRequirementDependingOnCoroutinesVersion(): Int = + writeVersionRequirement(LanguageFeature.ReleaseCoroutines) + + private fun CallableMemberDescriptor.isSuspendOrHasSuspendTypesInSignature(): Boolean { + if (this is FunctionDescriptor && isSuspend) return true + + return allTypesFromSignature().any { type -> type.contains(UnwrappedType::isSuspendFunctionTypeOrSubtype) } + } + private fun CallableMemberDescriptor.hasInlineClassTypesInSignature(): Boolean { return allTypesFromSignature().any { type -> type.contains(UnwrappedType::isInlineClassType) } } diff --git a/compiler/testData/versionRequirement/nestedClassMembers.kt b/compiler/testData/versionRequirement/nestedClassMembers.kt index 56a703a9169..ad651b2c192 100644 --- a/compiler/testData/versionRequirement/nestedClassMembers.kt +++ b/compiler/testData/versionRequirement/nestedClassMembers.kt @@ -12,6 +12,8 @@ class Outer { @RequireKotlin("1.3") val x = "" + + suspend fun s() {} } } diff --git a/compiler/testData/versionRequirement/suspendFun.kt b/compiler/testData/versionRequirement/suspendFun.kt new file mode 100644 index 00000000000..6e3777d81b7 --- /dev/null +++ b/compiler/testData/versionRequirement/suspendFun.kt @@ -0,0 +1,16 @@ +package test + +suspend fun topLevel() {} + +class Foo { + constructor(block: suspend () -> Unit) + + suspend fun member() {} +} + +fun async1(block: suspend () -> Unit) {} +fun (suspend () -> Unit).async2() {} +fun async3(): suspend () -> Unit = null!! +fun async4(): Map Unit>? = null + +val (suspend () -> Unit).asyncVal: () -> Unit get() = {} diff --git a/compiler/tests/org/jetbrains/kotlin/serialization/AbstractVersionRequirementTest.kt b/compiler/tests/org/jetbrains/kotlin/serialization/AbstractVersionRequirementTest.kt index ee6b9d26228..be276585535 100644 --- a/compiler/tests/org/jetbrains/kotlin/serialization/AbstractVersionRequirementTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/serialization/AbstractVersionRequirementTest.kt @@ -124,6 +124,23 @@ abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() { protected abstract fun loadModule(directory: File): ModuleDescriptor + fun testSuspendFun() { + doTest( + VersionRequirement.Version(1, 3), DeprecationLevel.ERROR, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null, + customLanguageVersion = LanguageVersion.KOTLIN_1_3, + fqNamesWithRequirements = listOf( + "test.topLevel", + "test.Foo.member", + "test.Foo.", + "test.async1", + "test.async2", + "test.async3", + "test.async4", + "test.asyncVal" + ) + ) + } + fun testDefinitelyNotNull() { doTest( VersionRequirement.Version(1, 7), DeprecationLevel.ERROR, null, ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION, null, @@ -204,6 +221,7 @@ abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() { "test.Outer.Inner.Deep.", "test.Outer.Inner.Deep.f", "test.Outer.Inner.Deep.x", + "test.Outer.Inner.Deep.s", "test.Outer.Nested.g", "test.Outer.Companion" ) diff --git a/libraries/tools/kotlinp/testData/SimpleClass.txt b/libraries/tools/kotlinp/testData/SimpleClass.txt index b63fda4f5a8..fb4d10a3e71 100644 --- a/libraries/tools/kotlinp/testData/SimpleClass.txt +++ b/libraries/tools/kotlinp/testData/SimpleClass.txt @@ -8,6 +8,7 @@ public final class SimpleClass : kotlin/Any { // signature: (I)V public constructor(p: kotlin/Int /* = ... */) + // requires language version 1.3.0 (level=ERROR) // signature: g(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; protected final inline suspend fun g(crossinline a: kotlin/Function0, noinline b: suspend kotlin/Function1, kotlin/Any?>): kotlin/Unit diff --git a/libraries/tools/kotlinp/testData/ValueClass.txt b/libraries/tools/kotlinp/testData/ValueClass.txt index 34a76f8efe8..6392bcbf063 100644 --- a/libraries/tools/kotlinp/testData/ValueClass.txt +++ b/libraries/tools/kotlinp/testData/ValueClass.txt @@ -31,6 +31,7 @@ public final value class A : kotlin/Any { // requires language version 1.3.0 (level=ERROR) public final value class B : kotlin/Any { + // requires language version 1.3.0 (level=ERROR) // requires language version 1.3.0 (level=ERROR) // signature: constructor-impl(Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; public constructor(f: suspend kotlin/Function1, kotlin/Any?>) @@ -44,6 +45,7 @@ public final value class B : kotlin/Any { // signature: toString-impl(Lkotlin/jvm/functions/Function1;)Ljava/lang/String; public open /* synthesized */ fun toString(): kotlin/String + // requires language version 1.3.0 (level=ERROR) // field: f:Lkotlin/jvm/functions/Function1; private final val f: suspend kotlin/Function1, kotlin/Any?> private final get