diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt index 1a1e7784ec6..9f0c6daa003 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt @@ -44,6 +44,7 @@ import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor.CoroutinesCompatibilityMode.* import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils @@ -104,10 +105,14 @@ private data class DeprecatedByOverridden(private val deprecations: Collection null + NEEDS_WRAPPER -> DeprecatedExperimentalCoroutine(target, WARNING) + INCOMPATIBLE -> DeprecatedExperimentalCoroutine(target, ERROR) + } + } private fun getDeprecationByVersionRequirement(target: DeclarationDescriptor): List { fun createVersion(version: String): MavenComparableVersion? = try { diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/library/experimental.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/library/experimental.kt index 2010ad4e448..ef7b4f22614 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/library/experimental.kt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/library/experimental.kt @@ -1,27 +1,14 @@ -suspend fun dummy() {} - -class C { - suspend fun dummy() = "OK" -} - -class WithNested { - class Nested { - suspend fun dummy() = "OK" - } -} - -class WithInner { - inner class Inner { - suspend fun dummy() = "OK" - } -} - val c: suspend () -> Unit = {} class WithTypeParameter Unit> {} fun returnsSuspend() : suspend() -> Unit = {} -fun builder(c: suspend () -> Unit) {} +fun Unit> withTypeParameter() = {} -fun Unit> withTypeParameter() = {} \ No newline at end of file +fun suspendFunctionNested(x: List Unit>) {} +fun suspendFunctionNestedInFunctionType(x: (suspend () -> Unit) -> Unit) {} + +fun suspendFunctionType3(x: suspend (Int, Int, Int) -> Unit) {} + +fun suspendVarargs(vararg x: suspend () -> Unit) {} diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/output.txt b/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/output.txt index 3097f812483..ef9768c9764 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/output.txt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/output.txt @@ -1,29 +1,30 @@ warning: language version 1.3 is experimental, there are no backwards compatibility guarantees for new language and library features -compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:2:5: error: using 'c: suspend () -> Unit' is an error. Experimental coroutine cannot be used with API version 1.3 - c() - ^ -compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:3:5: error: using 'constructor WithTypeParameter Unit>()' is an error. Experimental coroutine cannot be used with API version 1.3 +warning: runtime JAR files in the classpath should have the same version. These files were found in the classpath: + $DIST_DIR$/kotlin-stdlib-coroutines.jar (version 1.3) + $PROJECT_DIR$/lib/kotlin-stdlib.jar (version 1.2) + $PROJECT_DIR$/lib/kotlin-script-runtime.jar (version 1.2) + $PROJECT_DIR$/lib/kotlin-reflect.jar (version 1.2) +warning: consider providing an explicit dependency on kotlin-reflect 1.3 to prevent strange errors +warning: some runtime JAR files in the classpath have an incompatible version. Consider removing them from the classpath +compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:2:5: error: using 'constructor WithTypeParameter Unit>()' is an error. Experimental coroutine cannot be used with API version 1.3 WithTypeParameter Unit>() ^ -compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:4:5: error: using 'returnsSuspend(): suspend () -> Unit' is an error. Experimental coroutine cannot be used with API version 1.3 +compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:3:5: error: using 'returnsSuspend(): suspend () -> Unit' is an error. Experimental coroutine cannot be used with API version 1.3 returnsSuspend() ^ -compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:5:5: error: using 'builder(suspend () -> Unit): Unit' is an error. Experimental coroutine cannot be used with API version 1.3 - builder {} - ^ -compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:6:5: error: using 'withTypeParameter(): () -> Unit' is an error. Experimental coroutine cannot be used with API version 1.3 +compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:4:5: error: using 'withTypeParameter(): () -> Unit' is an error. Experimental coroutine cannot be used with API version 1.3 withTypeParameter Unit>() ^ -compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:8:5: error: using 'dummy(): Unit' is an error. Experimental coroutine cannot be used with API version 1.3 - dummy() +compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:6:5: error: using 'suspendFunctionNested(List Unit>): Unit' is an error. Experimental coroutine cannot be used with API version 1.3 + suspendFunctionNested(listOf(suspend { })) + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:7:5: error: using 'suspendFunctionNestedInFunctionType((suspend () -> Unit) -> Unit): Unit' is an error. Experimental coroutine cannot be used with API version 1.3 + suspendFunctionNestedInFunctionType {} + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:8:5: error: using 'suspendFunctionType3(suspend (Int, Int, Int) -> Unit): Unit' is an error. Experimental coroutine cannot be used with API version 1.3 + suspendFunctionType3 { x, y, z -> } + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:10:5: error: using 'suspendVarargs(vararg suspend () -> Unit): Unit' is an error. Experimental coroutine cannot be used with API version 1.3 + suspendVarargs({}, {}) ^ -compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:9:9: error: using 'dummy(): String' is an error. Experimental coroutine cannot be used with API version 1.3 - C().dummy() - ^ -compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:10:25: error: using 'dummy(): String' is an error. Experimental coroutine cannot be used with API version 1.3 - WithNested.Nested().dummy() - ^ -compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt:11:25: error: using 'dummy(): String' is an error. Experimental coroutine cannot be used with API version 1.3 - WithInner().Inner().dummy() - ^ COMPILATION_ERROR diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt index f3f4a20e43c..be722e56bac 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromRelease/release.kt @@ -1,12 +1,11 @@ suspend fun callRelease() { - c() WithTypeParameter Unit>() returnsSuspend() - builder {} withTypeParameter Unit>() - dummy() - C().dummy() - WithNested.Nested().dummy() - WithInner().Inner().dummy() + suspendFunctionNested(listOf(suspend { })) + suspendFunctionNestedInFunctionType {} + suspendFunctionType3 { x, y, z -> } + + suspendVarargs({}, {}) } diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/library/experimental.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/library/experimental.kt new file mode 100644 index 00000000000..9a0d87ffec6 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/library/experimental.kt @@ -0,0 +1,24 @@ +suspend fun dummy() {} + +class C { + suspend fun dummy() = "OK" +} + +class WithNested { + class Nested { + suspend fun dummy() = "OK" + } +} + +class WithInner { + inner class Inner { + suspend fun dummy() = "OK" + } +} + +fun builder(c: suspend () -> Unit) {} +fun builder2(c: suspend Int.(String) -> Unit) {} + +fun (suspend (Int) -> Unit).start() {} + +suspend fun suspendAcceptsSuspend(x: suspend () -> Unit) {} diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/output.txt b/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/output.txt new file mode 100644 index 00000000000..17e06a4085f --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/output.txt @@ -0,0 +1,33 @@ +warning: language version 1.3 is experimental, there are no backwards compatibility guarantees for new language and library features +warning: runtime JAR files in the classpath should have the same version. These files were found in the classpath: + $DIST_DIR$/kotlin-stdlib-coroutines.jar (version 1.3) + $PROJECT_DIR$/lib/kotlin-stdlib.jar (version 1.2) + $PROJECT_DIR$/lib/kotlin-script-runtime.jar (version 1.2) + $PROJECT_DIR$/lib/kotlin-reflect.jar (version 1.2) +warning: consider providing an explicit dependency on kotlin-reflect 1.3 to prevent strange errors +warning: some runtime JAR files in the classpath have an incompatible version. Consider removing them from the classpath +compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/release.kt:2:5: warning: 'builder(suspend () -> Unit): Unit' is deprecated. Experimental coroutines support will be dropped in 1.4 + builder {} + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/release.kt:3:5: warning: 'builder2(suspend Int.(String) -> Unit): Unit' is deprecated. Experimental coroutines support will be dropped in 1.4 + builder2 { } + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/release.kt:6:7: warning: 'start(): Unit' is deprecated. Experimental coroutines support will be dropped in 1.4 + x.start() + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/release.kt:8:5: warning: 'dummy(): Unit' is deprecated. Experimental coroutines support will be dropped in 1.4 + dummy() + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/release.kt:9:9: warning: 'dummy(): String' is deprecated. Experimental coroutines support will be dropped in 1.4 + C().dummy() + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/release.kt:10:25: warning: 'dummy(): String' is deprecated. Experimental coroutines support will be dropped in 1.4 + WithNested.Nested().dummy() + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/release.kt:11:25: warning: 'dummy(): String' is deprecated. Experimental coroutines support will be dropped in 1.4 + WithInner().Inner().dummy() + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/release.kt:13:5: warning: 'suspendAcceptsSuspend(suspend () -> Unit): Unit' is deprecated. Experimental coroutines support will be dropped in 1.4 + suspendAcceptsSuspend { + ^ +OK diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/release.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/release.kt new file mode 100644 index 00000000000..e31ac5b007d --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/experimentalCoroutineCallFromReleaseWarnings/release.kt @@ -0,0 +1,16 @@ +suspend fun callRelease() { + builder {} + builder2 { } + + val x: suspend (Int) -> Unit = {} + x.start() + + dummy() + C().dummy() + WithNested.Nested().dummy() + WithInner().Inner().dummy() + + suspendAcceptsSuspend { + callRelease() + } +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/release/languageVersionIsNotEqualToApiVersion.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/release/languageVersionIsNotEqualToApiVersion.kt index f7d8dbb9ade..20a995a6fc4 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/release/languageVersionIsNotEqualToApiVersion.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/release/languageVersionIsNotEqualToApiVersion.kt @@ -24,14 +24,14 @@ fun builder(c: suspend () -> Unit) {} } fun test2() { - kotlin.coroutines.experimental.buildSequence { - yield(1) + kotlin.coroutines.experimental.buildSequence { + yield(1) } kotlin.sequences.buildSequence { yield(1) } } -suspend fun test3(): Unit = kotlin.coroutines.experimental.suspendCoroutine { _ -> Unit } +suspend fun test3(): Unit = kotlin.coroutines.experimental.suspendCoroutine { _ -> Unit } -suspend fun test4(): Unit = kotlin.coroutines.suspendCoroutine { _ -> Unit } \ No newline at end of file +suspend fun test4(): Unit = kotlin.coroutines.suspendCoroutine { _ -> Unit } diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/cli/AbstractCliTest.java b/compiler/tests-common/tests/org/jetbrains/kotlin/cli/AbstractCliTest.java index 1e1af36c1ce..fcd6c81570e 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/cli/AbstractCliTest.java +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/cli/AbstractCliTest.java @@ -79,6 +79,7 @@ public abstract class AbstractCliTest extends TestCaseWithTmpdir { .replace(testDataAbsoluteDir, TESTDATA_DIR) .replace(FileUtil.toSystemIndependentName(testDataAbsoluteDir), TESTDATA_DIR) .replace(PathUtil.getKotlinPathsForDistDirectory().getHomePath().getAbsolutePath(), "$PROJECT_DIR$") + .replace(PathUtil.getKotlinPathsForDistDirectory().getHomePath().getParentFile().getAbsolutePath(), "$DIST_DIR$") .replace("expected version is " + JvmMetadataVersion.INSTANCE, "expected version is $ABI_VERSION$") .replace("expected version is " + JsMetadataVersion.INSTANCE, "expected version is $ABI_VERSION$") .replace("\\", "/") diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt index 366e48594f5..3a99f65ff46 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt @@ -484,6 +484,14 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration } fun testExperimentalCoroutineCallFromRelease() { + doTestExperimentalCoroutineCallFromRelease() + } + + fun testExperimentalCoroutineCallFromReleaseWarnings() { + doTestExperimentalCoroutineCallFromRelease() + } + + private fun doTestExperimentalCoroutineCallFromRelease() { val library = compileLibrary( "library", additionalOptions = listOf("-language-version", "1.2"), @@ -492,7 +500,7 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration compileKotlin( "release.kt", tmpdir, - listOf(library), + listOf(library, ForTestCompileRuntime.coroutinesJarForTests()), additionalOptions = listOf("-language-version", "1.3", "-api-version", "1.3") ) } diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt index bacb40bac3c..45549d07888 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.serialization.deserialization +import org.jetbrains.kotlin.builtins.isSuspendFunctionType import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget @@ -17,7 +18,12 @@ import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.* import org.jetbrains.kotlin.protobuf.MessageLite import org.jetbrains.kotlin.resolve.DescriptorFactory +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull import org.jetbrains.kotlin.serialization.deserialization.descriptors.* +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor.CoroutinesCompatibilityMode +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.UnwrappedType +import org.jetbrains.kotlin.types.typeUtil.contains class MemberDeserializer(private val c: DeserializationContext) { private val annotationDeserializer = AnnotationDeserializer(c.components.moduleDescriptor, c.components.notFoundClasses) @@ -130,12 +136,97 @@ class MemberDeserializer(private val c: DeserializationContext) { return property } - private fun DeserializedMemberDescriptor.checkExperimentalCoroutine(typeDeserializer: TypeDeserializer): Boolean { - // Calculate checkExperimentalCoroutine for type parameters - typeDeserializer.ownTypeParameters.forEach { it.upperBounds } - return typeDeserializer.experimentalSuspendFunctionTypeEncountered && versionAndReleaseCoroutinesMismatch() + private fun DeserializedMemberDescriptor.checkExperimentalCoroutine( + typeDeserializer: TypeDeserializer + ): DeserializedMemberDescriptor.CoroutinesCompatibilityMode { + if (!versionAndReleaseCoroutinesMismatch()) return CoroutinesCompatibilityMode.COMPATIBLE + + forceUpperBoundsComputation(typeDeserializer) + + return if (typeDeserializer.experimentalSuspendFunctionTypeEncountered) + CoroutinesCompatibilityMode.INCOMPATIBLE + else + CoroutinesCompatibilityMode.COMPATIBLE } + private fun forceUpperBoundsComputation(typeDeserializer: TypeDeserializer) { + typeDeserializer.ownTypeParameters.forEach { it.upperBounds } + } + + private fun DeserializedSimpleFunctionDescriptor.initializeWithCoroutinesExperimentalityStatus( + receiverParameterType: KotlinType?, + dispatchReceiverParameter: ReceiverParameterDescriptor?, + typeParameters: List, + unsubstitutedValueParameters: List, + unsubstitutedReturnType: KotlinType?, + modality: Modality?, + visibility: Visibility, + userDataMap: Map, *>, + isSuspend: Boolean + ) { + initialize( + receiverParameterType, + dispatchReceiverParameter, + typeParameters, + unsubstitutedValueParameters, + unsubstitutedReturnType, + modality, + visibility, + userDataMap, + computeExperimentalityModeForFunctions( + receiverParameterType, + unsubstitutedValueParameters, + typeParameters, + unsubstitutedReturnType, + isSuspend + ) + ) + } + + private fun DeserializedCallableMemberDescriptor.computeExperimentalityModeForFunctions( + extensionReceiverType: KotlinType?, + parameters: Collection, + typeParameters: Collection, + returnType: KotlinType?, + isSuspend: Boolean + ): DeserializedMemberDescriptor.CoroutinesCompatibilityMode { + if (!versionAndReleaseCoroutinesMismatch()) return CoroutinesCompatibilityMode.COMPATIBLE + if (fqNameOrNull() == KOTLIN_SUSPEND_BUILT_IN_FUNCTION_FQ_NAME) return CoroutinesCompatibilityMode.COMPATIBLE + + val types = parameters.map { it.type } + listOfNotNull(extensionReceiverType) + + if (returnType?.containsSuspendFunctionType() == true) return CoroutinesCompatibilityMode.INCOMPATIBLE + if (typeParameters.any { typeParameter -> typeParameter.upperBounds.any { it.containsSuspendFunctionType() } }) { + return CoroutinesCompatibilityMode.INCOMPATIBLE + } + + val maxFromParameters = types.map { type -> + when { + type.isSuspendFunctionType && type.arguments.size <= 3 -> + if (type.arguments.any { it.type.containsSuspendFunctionType() }) + CoroutinesCompatibilityMode.INCOMPATIBLE + else + CoroutinesCompatibilityMode.NEEDS_WRAPPER + + type.containsSuspendFunctionType() -> CoroutinesCompatibilityMode.INCOMPATIBLE + + else -> CoroutinesCompatibilityMode.COMPATIBLE + } + }.max() ?: CoroutinesCompatibilityMode.COMPATIBLE + + return maxOf( + if (isSuspend) + CoroutinesCompatibilityMode.NEEDS_WRAPPER + else + CoroutinesCompatibilityMode.COMPATIBLE, + maxFromParameters + ) + } + + + private fun KotlinType.containsSuspendFunctionType() = contains(UnwrappedType::isSuspendFunctionType) + + private fun DeserializedMemberDescriptor.versionAndReleaseCoroutinesMismatch(): Boolean = c.components.configuration.releaseCoroutines && versionRequirements.none { it.version == VersionRequirement.Version(1, 3) && it.kind == ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION @@ -160,7 +251,7 @@ class MemberDeserializer(private val c: DeserializationContext) { ) val local = c.childContext(function, proto.typeParameterList) - function.initialize( + function.initializeWithCoroutinesExperimentalityStatus( proto.receiverType(c.typeTable)?.let { local.typeDeserializer.type(it, receiverAnnotations) }, getDispatchReceiverParameter(), local.typeDeserializer.ownTypeParameters, @@ -169,8 +260,7 @@ class MemberDeserializer(private val c: DeserializationContext) { ProtoEnumFlags.modality(Flags.MODALITY.get(flags)), ProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags)), emptyMap, Any?>(), - (Flags.IS_SUSPEND.get(flags) && function.versionAndReleaseCoroutinesMismatch()) || - function.checkExperimentalCoroutine(local.typeDeserializer) + Flags.IS_SUSPEND.get(flags) ) function.isOperator = Flags.IS_OPERATOR.get(flags) function.isInfix = Flags.IS_INFIX.get(flags) @@ -227,11 +317,18 @@ class MemberDeserializer(private val c: DeserializationContext) { ) descriptor.returnType = classDescriptor.defaultType - // Calculate isExperimentalCoroutineInReleaseEnvironment for type parameters - descriptor.typeParameters.forEach { it.upperBounds } - descriptor.isExperimentalCoroutineInReleaseEnvironment = local.typeDeserializer.experimentalSuspendFunctionTypeEncountered || - ((c.containingDeclaration as? DeserializedClassDescriptor)?.c?.typeDeserializer?.experimentalSuspendFunctionTypeEncountered == true && - descriptor.versionAndReleaseCoroutinesMismatch()) + val doesClassContainIncompatibility = + (c.containingDeclaration as? DeserializedClassDescriptor) + ?.c?.typeDeserializer?.experimentalSuspendFunctionTypeEncountered == true + && descriptor.versionAndReleaseCoroutinesMismatch() + + descriptor.coroutinesExperimentalCompatibilityMode = + if (doesClassContainIncompatibility) + CoroutinesCompatibilityMode.INCOMPATIBLE + else descriptor.computeExperimentalityModeForFunctions( + null, descriptor.valueParameters, descriptor.typeParameters, + descriptor.returnType, isSuspend = false + ) return descriptor } diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberDescriptor.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberDescriptor.kt index 5d104f2e2b4..06c2dcdb8e1 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberDescriptor.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberDescriptor.kt @@ -23,8 +23,6 @@ interface DeserializedMemberDescriptor : MemberDescriptor { val typeTable: TypeTable - val isExperimentalCoroutineInReleaseEnvironment: Boolean - val versionRequirementTable: VersionRequirementTable val versionRequirements: List @@ -33,6 +31,14 @@ interface DeserializedMemberDescriptor : MemberDescriptor { // Information about the origin of this callable's container (class or package part on JVM) or null if there's no such information. // TODO: merge with sourceElement of containingDeclaration val containerSource: DeserializedContainerSource? + + val coroutinesExperimentalCompatibilityMode: CoroutinesCompatibilityMode + + enum class CoroutinesCompatibilityMode { + COMPATIBLE, + NEEDS_WRAPPER, + INCOMPATIBLE + } } interface DeserializedContainerSource : SourceElement { @@ -66,7 +72,7 @@ class DeserializedSimpleFunctionDescriptor( source ?: SourceElement.NO_SOURCE ) { - override var isExperimentalCoroutineInReleaseEnvironment: Boolean = false + override var coroutinesExperimentalCompatibilityMode = DeserializedMemberDescriptor.CoroutinesCompatibilityMode.COMPATIBLE private set fun initialize( @@ -78,7 +84,7 @@ class DeserializedSimpleFunctionDescriptor( modality: Modality?, visibility: Visibility, userDataMap: Map, *>, - isExperimentalCoroutineInReleaseEnvironment: Boolean + isExperimentalCoroutineInReleaseEnvironment: DeserializedMemberDescriptor.CoroutinesCompatibilityMode ): SimpleFunctionDescriptorImpl { return super.initialize( receiverParameterType, @@ -90,7 +96,7 @@ class DeserializedSimpleFunctionDescriptor( visibility, userDataMap ).also { - this.isExperimentalCoroutineInReleaseEnvironment = isExperimentalCoroutineInReleaseEnvironment + this.coroutinesExperimentalCompatibilityMode = isExperimentalCoroutineInReleaseEnvironment } } @@ -105,7 +111,9 @@ class DeserializedSimpleFunctionDescriptor( return DeserializedSimpleFunctionDescriptor( newOwner, original as SimpleFunctionDescriptor?, annotations, newName ?: name, kind, proto, nameResolver, typeTable, versionRequirementTable, containerSource, source - ) + ).also { + it.coroutinesExperimentalCompatibilityMode = coroutinesExperimentalCompatibilityMode + } } } @@ -132,16 +140,16 @@ class DeserializedPropertyDescriptor( containingDeclaration, original, annotations, modality, visibility, isVar, name, kind, SourceElement.NO_SOURCE, isLateInit, isConst, isExpect, false, isExternal, isDelegated ) { - override var isExperimentalCoroutineInReleaseEnvironment: Boolean = false + override var coroutinesExperimentalCompatibilityMode = DeserializedMemberDescriptor.CoroutinesCompatibilityMode.COMPATIBLE private set fun initialize( getter: PropertyGetterDescriptorImpl?, setter: PropertySetterDescriptor?, - isExperimentalCoroutineInReleaseEnvironment: Boolean + isExperimentalCoroutineInReleaseEnvironment: DeserializedMemberDescriptor.CoroutinesCompatibilityMode ) { super.initialize(getter, setter) - .also { this.isExperimentalCoroutineInReleaseEnvironment = isExperimentalCoroutineInReleaseEnvironment } + .also { this.coroutinesExperimentalCompatibilityMode = isExperimentalCoroutineInReleaseEnvironment } } override fun createSubstitutedCopy( @@ -176,7 +184,7 @@ class DeserializedClassConstructorDescriptor( ) : DeserializedCallableMemberDescriptor, ClassConstructorDescriptorImpl(containingDeclaration, original, annotations, isPrimary, kind, source ?: SourceElement.NO_SOURCE) { - override var isExperimentalCoroutineInReleaseEnvironment: Boolean = false + override var coroutinesExperimentalCompatibilityMode = DeserializedMemberDescriptor.CoroutinesCompatibilityMode.COMPATIBLE internal set override fun createSubstitutedCopy( @@ -190,7 +198,7 @@ class DeserializedClassConstructorDescriptor( return DeserializedClassConstructorDescriptor( newOwner as ClassDescriptor, original as ConstructorDescriptor?, annotations, isPrimary, kind, proto, nameResolver, typeTable, versionRequirementTable, containerSource, source - ).also { it.isExperimentalCoroutineInReleaseEnvironment = isExperimentalCoroutineInReleaseEnvironment } + ).also { it.coroutinesExperimentalCompatibilityMode = coroutinesExperimentalCompatibilityMode } } override fun isExternal(): Boolean = false @@ -222,14 +230,14 @@ class DeserializedTypeAliasDescriptor( private lateinit var typeConstructorParameters: List private lateinit var defaultTypeImpl: SimpleType - override var isExperimentalCoroutineInReleaseEnvironment: Boolean = false + override var coroutinesExperimentalCompatibilityMode = DeserializedMemberDescriptor.CoroutinesCompatibilityMode.COMPATIBLE private set fun initialize( declaredTypeParameters: List, underlyingType: SimpleType, expandedType: SimpleType, - isExperimentalCoroutineInReleaseEnvironment: Boolean + isExperimentalCoroutineInReleaseEnvironment: DeserializedMemberDescriptor.CoroutinesCompatibilityMode ) { initialize(declaredTypeParameters) this.underlyingType = underlyingType @@ -237,7 +245,7 @@ class DeserializedTypeAliasDescriptor( typeConstructorParameters = computeConstructorTypeParameters() defaultTypeImpl = computeDefaultType() constructors = getTypeAliasConstructors() - this.isExperimentalCoroutineInReleaseEnvironment = isExperimentalCoroutineInReleaseEnvironment + this.coroutinesExperimentalCompatibilityMode = isExperimentalCoroutineInReleaseEnvironment } override val classDescriptor: ClassDescriptor? @@ -255,7 +263,7 @@ class DeserializedTypeAliasDescriptor( declaredTypeParameters, substitutor.safeSubstitute(underlyingType, Variance.INVARIANT).asSimpleType(), substitutor.safeSubstitute(expandedType, Variance.INVARIANT).asSimpleType(), - isExperimentalCoroutineInReleaseEnvironment + coroutinesExperimentalCompatibilityMode ) return substituted diff --git a/idea/testData/multiModuleHighlighting/coroutineMixedReleaseStatus/moduleNew/main.kt b/idea/testData/multiModuleHighlighting/coroutineMixedReleaseStatus/moduleNew/main.kt index 365312f5332..35af8246e12 100644 --- a/idea/testData/multiModuleHighlighting/coroutineMixedReleaseStatus/moduleNew/main.kt +++ b/idea/testData/multiModuleHighlighting/coroutineMixedReleaseStatus/moduleNew/main.kt @@ -3,7 +3,7 @@ import libO.* suspend fun newMain() { newFoo() - oldFoo() + oldFoo() // TODO: actually, it's a bug oldMain() @@ -14,5 +14,5 @@ fun newMain2() { newMain() } - oldFoo() + oldFoo() }