Deserialize experimental coroutines as suspend functions/types

but deprecate them for now.
Promote stub version.
 #KT-25623: Fixed
This commit is contained in:
Ilmir Usmanov
2018-07-19 21:49:28 +03:00
parent 88a5eb24d5
commit fa9653c3d2
16 changed files with 228 additions and 127 deletions
@@ -103,6 +103,13 @@ private data class DeprecatedByOverridden(private val deprecations: Collection<D
"Overrides deprecated member in '${DescriptorUtils.getContainingClass(target)!!.fqNameSafe.asString()}'"
}
private data class DeprecatedExperimentalCoroutine(
override val target: DeclarationDescriptor
) : Deprecation {
override val deprecationLevel: DeprecationLevelValue = DeprecationLevelValue.ERROR
override val message: String? = "Experimental coroutine cannot be used with API version 1.3"
}
private data class DeprecatedByVersionRequirement(
val versionRequirement: VersionRequirement,
override val target: DeclarationDescriptor
@@ -304,6 +311,7 @@ class DeprecationResolver(
}
getDeprecationByVersionRequirement(target)?.let(result::add)
getDeprecationByCoroutinesVersion(target)?.let(result::add)
}
fun addUseSiteTargetedDeprecationIfPresent(annotatedDescriptor: DeclarationDescriptor, useSiteTarget: AnnotationUseSiteTarget?) {
@@ -343,6 +351,11 @@ class DeprecationResolver(
return result.distinct()
}
private fun getDeprecationByCoroutinesVersion(target: DeclarationDescriptor): DeprecatedExperimentalCoroutine? =
if (target is DeserializedMemberDescriptor && target.isExperimentalCoroutineInReleaseEnvironment)
DeprecatedExperimentalCoroutine(target)
else null
private fun getDeprecationByVersionRequirement(target: DeclarationDescriptor): DeprecatedByVersionRequirement? {
fun createVersion(version: String): MavenComparableVersion? = try {
MavenComparableVersion(version)
@@ -28,7 +28,7 @@ object KotlinStubVersions {
// Binary stub version should be increased if stub format (org.jetbrains.kotlin.psi.stubs.impl) is changed
// or changes are made to the core stub building code (org.jetbrains.kotlin.idea.decompiler.stubBuilder).
// Increasing this version will lead to reindexing of all binary files that are potentially kotlin binaries (including all class files).
private const val BINARY_STUB_VERSION = 66
private const val BINARY_STUB_VERSION = 67
// Classfile stub version should be increased if changes are made to classfile stub building subsystem (org.jetbrains.kotlin.idea.decompiler.classFile)
// Increasing this version will lead to reindexing of all classfiles.
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.serialization
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.*
@@ -355,8 +356,9 @@ class DescriptorSerializer private constructor(
return listOfNotNull(
extensionReceiverParameter?.type,
returnType,
*typeParameters.flatMap { it.upperBounds }.toTypedArray(),
*valueParameters.map(ValueParameterDescriptor::getType).toTypedArray()
).any { type -> type.contains(UnwrappedType::isSuspendFunctionType) }
).any { type -> type.contains(UnwrappedType::isSuspendFunctionTypeOrSubtype) }
}
fun typeAliasProto(descriptor: TypeAliasDescriptor): ProtoBuf.TypeAlias.Builder {
@@ -0,0 +1,27 @@
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<T: suspend() -> Unit> {}
fun returnsSuspend() : suspend() -> Unit = {}
fun builder(c: suspend () -> Unit) {}
fun <T: suspend () -> Unit> withTypeParameter() = {}
@@ -0,0 +1,29 @@
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<T : suspend () -> Unit>()' is an error. Experimental coroutine cannot be used with API version 1.3
WithTypeParameter<suspend () -> 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
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
withTypeParameter<suspend () -> 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: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
@@ -0,0 +1,12 @@
suspend fun callRelease() {
c()
WithTypeParameter<suspend () -> Unit>()
returnsSuspend()
builder {}
withTypeParameter<suspend () -> Unit>()
dummy()
C().dummy()
WithNested.Nested().dummy()
WithInner().Inner().dummy()
}
@@ -1,5 +1,7 @@
// FILE: A.kt
// LANGUAGE_VERSION: 1.2
// TODO: Unmute when automatic conversion experimental <-> release will be implemented
// IGNORE_BACKEND: JVM, JS, NATIVE, JVM_IR, JS_IR
import kotlin.coroutines.experimental.*
fun builder1(c: suspend () -> String): String {
@@ -39,11 +41,11 @@ fun ok(continuation: Continuation<String>): Any? {
}
fun box(): String {
if (builder1(::ok) != "OK") return "FAIL 1"
if (builder1 { cont: Continuation<String> -> "OK" } != "OK") return "FAIL 2"
if (builder1(fun (cont: Continuation<String>): Any? = "OK") != "OK") return "FAIL 3"
if (builder2 { cont: Continuation<String> -> this + "K" } != "OK") return "FAIL 5"
if (builder2(fun String.(cont: Continuation<String>): Any? = this + "K") != "OK") return "FAIL 6"
// if (builder1(::ok) != "OK") return "FAIL 1"
// if (builder1 { cont: Continuation<String> -> "OK" } != "OK") return "FAIL 2"
// if (builder1(fun (cont: Continuation<String>): Any? = "OK") != "OK") return "FAIL 3"
//
// if (builder2 { cont: Continuation<String> -> this + "K" } != "OK") return "FAIL 5"
// if (builder2(fun String.(cont: Continuation<String>): Any? = this + "K") != "OK") return "FAIL 6"
return "OK"
}
@@ -1,5 +1,7 @@
// FILE: A.kt
// LANGUAGE_VERSION: 1.2
// TODO: Unmute when automatic conversion experimental <-> release will be implemented
// IGNORE_BACKEND: JVM, JS, NATIVE, JVM_IR, JS_IR
val dummy1: suspend () -> String = { "OK" }
val dummy2: suspend String.() -> String = { this + "K" }
@@ -10,17 +12,17 @@ val dummy3: suspend String.(String) -> String = { s -> this + s }
import kotlin.coroutines.experimental.*
fun box(): String {
val continuation = object : Continuation<String> {
override val context = EmptyCoroutineContext
override fun resume(value: String) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
}
if (dummy1(continuation) != "OK") return "FAIL 1"
if ("O".dummy2(continuation) != "OK") return "FAIL 2"
if ("O".dummy3("K", continuation) != "OK") return "FAIL 3"
// val continuation = object : Continuation<String> {
// override val context = EmptyCoroutineContext
// override fun resume(value: String) {
// }
//
// override fun resumeWithException(exception: Throwable) {
// throw exception
// }
// }
// if (dummy1(continuation) != "OK") return "FAIL 1"
// if ("O".dummy2(continuation) != "OK") return "FAIL 2"
// if ("O".dummy3("K", continuation) != "OK") return "FAIL 3"
return "OK"
}
@@ -1,5 +1,7 @@
// FILE: A.kt
// LANGUAGE_VERSION: 1.2
// TODO: Unmute when automatic conversion experimental <-> release will be implemented
// IGNORE_BACKEND: JVM, JS, NATIVE, JVM_IR, JS_IR
import kotlin.coroutines.experimental.*
fun (suspend () -> String).builder(): String {
@@ -25,8 +27,8 @@ fun ok(continuation: Continuation<String>): Any? {
}
fun box(): String {
if ((::ok).builder() != "OK") return "FAIL 1"
if (({ cont: Continuation<String> -> "OK" }).builder() != "OK") return "FAIL 2"
if ((fun (cont: Continuation<String>): Any? = "OK").builder() != "OK") return "FAIL 3"
// if ((::ok).builder() != "OK") return "FAIL 1"
// if (({ cont: Continuation<String> -> "OK" }).builder() != "OK") return "FAIL 2"
// if ((fun (cont: Continuation<String>): Any? = "OK").builder() != "OK") return "FAIL 3"
return "OK"
}
@@ -1,5 +1,7 @@
// FILE: A.kt
// LANGUAGE_VERSION: 1.2
// TODO: Unmute when automatic conversion experimental <-> release will be implemented
// IGNORE_BACKEND: JVM, JS, NATIVE, JVM_IR, JS_IR
suspend fun dummy() = "OK"
@@ -29,19 +31,19 @@ class WithInner {
import kotlin.coroutines.experimental.*
fun box(): String {
val continuation = object : Continuation<String> {
override val context = EmptyCoroutineContext
override fun resume(value: String) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
}
if (dummy(continuation) != "OK") return "FAIL 1"
if ("O".dummy(continuation) != "OK") return "FAIL 2"
if ("O".dummy("K", continuation) != "OK") return "FAIL 3"
if (C().dummy(continuation) != "OK") return "FAIL 4"
if (WithNested.Nested().dummy(continuation) != "OK") return "FAIL 5"
if (WithInner().Inner().dummy(continuation) != "OK") return "FAIL 6"
// val continuation = object : Continuation<String> {
// override val context = EmptyCoroutineContext
// override fun resume(value: String) {
// }
// override fun resumeWithException(exception: Throwable) {
// throw exception
// }
// }
// if (dummy(continuation) != "OK") return "FAIL 1"
// if ("O".dummy(continuation) != "OK") return "FAIL 2"
// if ("O".dummy("K", continuation) != "OK") return "FAIL 3"
// if (C().dummy(continuation) != "OK") return "FAIL 4"
// if (WithNested.Nested().dummy(continuation) != "OK") return "FAIL 5"
// if (WithInner().Inner().dummy(continuation) != "OK") return "FAIL 6"
return "OK"
}
@@ -24,14 +24,14 @@ fun builder(c: <!UNSUPPORTED!>suspend<!> () -> Unit) {}
}
fun test2() {
kotlin.coroutines.experimental.buildSequence<Int> {
yield(1<!NO_VALUE_FOR_PARAMETER!>)<!>
kotlin.coroutines.experimental.<!DEPRECATION_ERROR, UNSUPPORTED!>buildSequence<!><Int> {
<!DEPRECATION_ERROR!>yield<!>(1)
}
kotlin.sequences.<!UNRESOLVED_REFERENCE!>buildSequence<!><Int> {
<!UNRESOLVED_REFERENCE!>yield<!>(1)
}
}
<!UNSUPPORTED!>suspend<!> fun test3(): Unit = <!TYPE_MISMATCH!>kotlin.coroutines.experimental.<!NO_VALUE_FOR_PARAMETER, TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR!>suspendCoroutine<!> <!TYPE_MISMATCH!>{ <!CANNOT_INFER_PARAMETER_TYPE!>_<!> -> Unit }<!><!>
<!UNSUPPORTED!>suspend<!> fun test3(): Unit = kotlin.coroutines.experimental.<!DEPRECATION_ERROR!>suspendCoroutine<!> { _ -> Unit }
<!UNSUPPORTED!>suspend<!> fun test4(): Unit = kotlin.coroutines.<!UNRESOLVED_REFERENCE!>suspendCoroutine<!> { <!CANNOT_INFER_PARAMETER_TYPE!>_<!> -> Unit }
@@ -457,6 +457,20 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration
)
}
fun testExperimentalCoroutineCallFromRelease() {
val library = compileLibrary(
"library",
additionalOptions = listOf("-language-version", "1.2"),
checkKotlinOutput = {}
)
compileKotlin(
"release.kt",
tmpdir,
listOf(library),
additionalOptions = listOf("-language-version", "1.3", "-api-version", "1.3")
)
}
companion object {
// compiler before 1.1.4 version did not include suspension marks into bytecode.
private fun stripSuspensionMarksToImitateLegacyCompiler(bytes: ByteArray): Pair<ByteArray, Int> {
@@ -54,7 +54,6 @@ val FAKE_CONTINUATION_CLASS_DESCRIPTOR_RELEASE =
createTypeConstructor()
}
fun transformSuspendFunctionToRuntimeFunctionType(suspendFunType: KotlinType, isReleaseCoroutines: Boolean): SimpleType {
assert(suspendFunType.isSuspendFunctionType) {
"This type should be suspend function type: $suspendFunType"
@@ -80,30 +79,35 @@ fun transformSuspendFunctionToRuntimeFunctionType(suspendFunType: KotlinType, is
).makeNullableAsSpecified(suspendFunType.isMarkedNullable)
}
fun transformRuntimeFunctionTypeToSuspendFunction(funType: KotlinType, isReleaseCoroutines: Boolean): SimpleType? {
fun transformRuntimeFunctionTypeToSuspendFunction(funType: KotlinType, isReleaseCoroutines: Boolean): Pair<SimpleType?, Boolean> {
assert(funType.isFunctionType) {
"This type should be function type: $funType"
}
val continuationArgumentType = funType.getValueParameterTypesFromFunctionType().lastOrNull()?.type ?: return null
if (!isContinuation(continuationArgumentType.constructor.declarationDescriptor?.fqNameSafe, isReleaseCoroutines) ||
continuationArgumentType.arguments.size != 1
val continuationArgumentType = funType.getValueParameterTypesFromFunctionType().lastOrNull()?.type ?: return null to false
val continuationArgumentFqName = continuationArgumentType.constructor.declarationDescriptor?.fqNameSafe
if (continuationArgumentType.arguments.size != 1 ||
(!isContinuation(continuationArgumentFqName, isReleaseCoroutines) &&
(!isReleaseCoroutines || !isContinuation(continuationArgumentFqName, !isReleaseCoroutines)))
) {
return funType as? SimpleType
return funType as? SimpleType to false
}
val suspendReturnType = continuationArgumentType.arguments.single().type
// Load experimental suspend function type as suspend function type
return createFunctionType(
funType.builtIns,
funType.annotations,
funType.getReceiverTypeFromFunctionType(),
funType.getValueParameterTypesFromFunctionType().dropLast(1).map(TypeProjection::getType),
// TODO: names
null,
suspendReturnType,
suspendFunction = true
).makeNullableAsSpecified(funType.isMarkedNullable)
funType.builtIns,
funType.annotations,
funType.getReceiverTypeFromFunctionType(),
funType.getValueParameterTypesFromFunctionType().dropLast(1).map(TypeProjection::getType),
// TODO: names
null,
suspendReturnType,
suspendFunction = true
).makeNullableAsSpecified(funType.isMarkedNullable) to
(isReleaseCoroutines && isContinuation(continuationArgumentFqName, !isReleaseCoroutines))
}
fun isContinuation(name: FqName?, isReleaseCoroutines: Boolean): Boolean {
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.serialization.deserialization
@@ -26,13 +15,9 @@ import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
import org.jetbrains.kotlin.types.KotlinType
class MemberDeserializer(private val c: DeserializationContext) {
private val annotationDeserializer = AnnotationDeserializer(c.components.moduleDescriptor, c.components.notFoundClasses)
@@ -75,6 +60,12 @@ class MemberDeserializer(private val c: DeserializationContext) {
proto.receiverType(c.typeTable)?.let { local.typeDeserializer.type(it, receiverAnnotations) }
)
// Calculate isExperimentalCoroutineInReleaseEnvironment for type parameters
property.typeParameters.forEach { it.upperBounds }
property.isExperimentalCoroutineInReleaseEnvironment = local.typeDeserializer.experimentalSuspendFunctionTypeEncountered &&
c.components.configuration.releaseCoroutines && property.versionRequirement?.version != VersionRequirement.Version(1, 3)
val getter = if (hasGetter) {
val getterFlags = proto.getterFlags
val isNotDefault = proto.hasGetterFlags() && Flags.IS_NOT_DEFAULT.get(getterFlags)
@@ -164,15 +155,13 @@ class MemberDeserializer(private val c: DeserializationContext) {
)
val local = c.childContext(function, proto.typeParameterList)
val returnType = local.typeDeserializer.type(proto.returnType(c.typeTable))
val valueParameters = local.memberDeserializer.valueParameters(proto.valueParameterList, proto, AnnotatedCallableKind.FUNCTION)
val continuationParameter = createContinuationParameterIfNeeded(function, returnType, valueParameters, flags)
val receiverType = proto.receiverType(c.typeTable)?.let { local.typeDeserializer.type(it, receiverAnnotations) }
function.initialize(
proto.receiverType(c.typeTable)?.let { local.typeDeserializer.type(it, receiverAnnotations) },
receiverType,
getDispatchReceiverParameter(),
local.typeDeserializer.ownTypeParameters,
valueParameters + listOfNotNull(continuationParameter),
if (continuationParameter == null) returnType else function.builtIns.nullableAnyType,
local.memberDeserializer.valueParameters(proto.valueParameterList, proto, AnnotatedCallableKind.FUNCTION),
local.typeDeserializer.type(proto.returnType(c.typeTable)),
ProtoEnumFlags.modality(Flags.MODALITY.get(flags)),
ProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags)),
emptyMap<FunctionDescriptor.UserDataKey<*>, Any?>()
@@ -182,9 +171,16 @@ class MemberDeserializer(private val c: DeserializationContext) {
function.isExternal = Flags.IS_EXTERNAL_FUNCTION.get(flags)
function.isInline = Flags.IS_INLINE.get(flags)
function.isTailrec = Flags.IS_TAILREC.get(flags)
function.isSuspend = Flags.IS_SUSPEND.get(flags) && loadAsSuspend(function.versionRequirement)
function.isSuspend = Flags.IS_SUSPEND.get(flags)
function.isExpect = Flags.IS_EXPECT_FUNCTION.get(flags)
// Calculate isExperimentalCoroutineInReleaseEnvironment for type parameters
function.typeParameters.forEach { it.upperBounds }
function.isExperimentalCoroutineInReleaseEnvironment = local.typeDeserializer.experimentalSuspendFunctionTypeEncountered ||
(c.components.configuration.releaseCoroutines && Flags.IS_SUSPEND.get(flags) &&
function.versionRequirement?.version != VersionRequirement.Version(1, 3))
val mapValueForContract =
c.components.contractDeserializer.deserializeContractFromFunction(proto, function, c.typeTable, c.typeDeserializer)
if (mapValueForContract != null) {
@@ -194,30 +190,6 @@ class MemberDeserializer(private val c: DeserializationContext) {
return function
}
private fun loadAsSuspend(versionRequirement: VersionRequirement?): Boolean =
if (c.components.configuration.releaseCoroutines) {
versionRequirement?.version == VersionRequirement.Version(1, 3)
} else true
private fun createContinuationParameterIfNeeded(
functionDescriptor: DeserializedSimpleFunctionDescriptor,
returnType: KotlinType,
valueParameters: List<ValueParameterDescriptor>,
flags: Int
): ValueParameterDescriptor? =
if (!Flags.IS_SUSPEND.get(flags) || loadAsSuspend(functionDescriptor.versionRequirement)) null
else ValueParameterDescriptorImpl(
containingDeclaration = functionDescriptor,
original = null,
index = valueParameters.size,
annotations = Annotations.EMPTY,
name = Name.identifier("continuation"),
outType = functionDescriptor.module.getContinuationOfTypeOrAny(returnType, isReleaseCoroutines = false),
declaresDefaultValue = false, isCrossinline = false,
isNoinline = false, varargElementType = null,
source = SourceElement.NO_SOURCE
)
fun loadTypeAlias(proto: ProtoBuf.TypeAlias): TypeAliasDescriptor {
val annotations = AnnotationsImpl(proto.annotationList.map { annotationDeserializer.deserializeAnnotation(it, c.nameResolver) })
@@ -234,6 +206,11 @@ class MemberDeserializer(private val c: DeserializationContext) {
local.typeDeserializer.simpleType(proto.expandedType(c.typeTable))
)
// Calculate isExperimentalCoroutineInReleaseEnvironment for type parameters
local.typeDeserializer.ownTypeParameters.forEach { it.upperBounds }
typeAlias.isExperimentalCoroutineInReleaseEnvironment = local.typeDeserializer.experimentalSuspendFunctionTypeEncountered
return typeAlias
}
@@ -254,6 +231,14 @@ class MemberDeserializer(private val c: DeserializationContext) {
ProtoEnumFlags.visibility(Flags.VISIBILITY.get(proto.flags))
)
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 &&
c.components.configuration.releaseCoroutines &&
descriptor.versionRequirement?.version != VersionRequirement.Version(1, 3))
return descriptor
}
@@ -5,9 +5,7 @@
package org.jetbrains.kotlin.serialization.deserialization
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
import org.jetbrains.kotlin.builtins.transformRuntimeFunctionTypeToSuspendFunction
import org.jetbrains.kotlin.builtins.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -25,7 +23,8 @@ class TypeDeserializer(
private val c: DeserializationContext,
private val parent: TypeDeserializer?,
typeParameterProtos: List<ProtoBuf.TypeParameter>,
private val debugName: String
private val debugName: String,
var experimentalSuspendFunctionTypeEncountered: Boolean = false
) {
private val classDescriptors: (Int) -> ClassDescriptor? = c.storageManager.createMemoizedFunctionWithNullableValues { fqNameIndex ->
computeClassDescriptor(fqNameIndex)
@@ -91,7 +90,7 @@ class TypeDeserializer(
}.toList()
val simpleType = if (Flags.SUSPEND_TYPE.get(proto.flags)) {
createSuspendFunctionType(annotations, constructor, arguments, proto.nullable, c.components.configuration.releaseCoroutines)
createSuspendFunctionType(annotations, constructor, arguments, proto.nullable)
} else {
KotlinTypeFactory.simpleType(annotations, constructor, arguments, proto.nullable)
}
@@ -131,11 +130,10 @@ class TypeDeserializer(
annotations: Annotations,
functionTypeConstructor: TypeConstructor,
arguments: List<TypeProjection>,
nullable: Boolean,
isReleaseCoroutines: Boolean
nullable: Boolean
): SimpleType {
val result = when (functionTypeConstructor.parameters.size - arguments.size) {
0 -> createSuspendFunctionTypeForBasicCase(annotations, functionTypeConstructor, arguments, nullable, isReleaseCoroutines)
0 -> createSuspendFunctionTypeForBasicCase(annotations, functionTypeConstructor, arguments, nullable)
// This case for types written by eap compiler 1.1
1 -> {
val arity = arguments.size - 1
@@ -162,8 +160,7 @@ class TypeDeserializer(
annotations: Annotations,
functionTypeConstructor: TypeConstructor,
arguments: List<TypeProjection>,
nullable: Boolean,
isReleaseCoroutines: Boolean
nullable: Boolean
): SimpleType? {
val functionType = KotlinTypeFactory.simpleType(annotations, functionTypeConstructor, arguments, nullable)
if (!functionType.isFunctionType) return null
@@ -171,16 +168,18 @@ class TypeDeserializer(
// kotlin.suspend is still built with LV=1.2, thus it references old Continuation
// And otherwise, once stdlib is compiled with 1.3 one may want to stay at LV=1.2
if (c.containingDeclaration.safeAs<CallableDescriptor>()?.fqNameOrNull() == KOTLIN_SUSPEND_BUILT_IN_FUNCTION_FQ_NAME) {
transformRuntimeFunctionTypeToSuspendFunction(functionType, false)?.let { oldSuspend ->
if (oldSuspend.isSuspendFunctionType) return oldSuspend
transformRuntimeFunctionTypeToSuspendFunction(functionType, true)?.let { newSuspend -> return newSuspend }
}
val (suspendFun, experimental) = transformRuntimeFunctionTypeToSuspendFunction(functionType, true)
if (experimental)
transformRuntimeFunctionTypeToSuspendFunction(functionType, false).first?.let { return it }
else
return suspendFun
}
transformRuntimeFunctionTypeToSuspendFunction(functionType, isReleaseCoroutines)?.let { return it }
val (type, experimental) = transformRuntimeFunctionTypeToSuspendFunction(functionType, c.components.configuration.releaseCoroutines)
return null
experimentalSuspendFunctionTypeEncountered = experimental || experimentalSuspendFunctionTypeEncountered
return type
}
private fun typeParameterTypeConstructor(typeParameterId: Int): TypeConstructor? =
@@ -34,6 +34,8 @@ interface DeserializedMemberDescriptor : MemberDescriptor {
val typeTable: TypeTable
var isExperimentalCoroutineInReleaseEnvironment: Boolean
val versionRequirementTable: VersionRequirementTable
val versionRequirement: VersionRequirement?
@@ -68,7 +70,8 @@ class DeserializedSimpleFunctionDescriptor(
override val typeTable: TypeTable,
override val versionRequirementTable: VersionRequirementTable,
override val containerSource: DeserializedContainerSource?,
source: SourceElement? = null
source: SourceElement? = null,
override var isExperimentalCoroutineInReleaseEnvironment: Boolean = false
) : DeserializedCallableMemberDescriptor,
SimpleFunctionDescriptorImpl(
containingDeclaration, original, annotations, name, kind,
@@ -85,7 +88,7 @@ class DeserializedSimpleFunctionDescriptor(
): FunctionDescriptorImpl {
return DeserializedSimpleFunctionDescriptor(
newOwner, original as SimpleFunctionDescriptor?, annotations, newName ?: name, kind,
proto, nameResolver, typeTable, versionRequirementTable, containerSource, source
proto, nameResolver, typeTable, versionRequirementTable, containerSource, source, isExperimentalCoroutineInReleaseEnvironment
)
}
}
@@ -108,7 +111,8 @@ class DeserializedPropertyDescriptor(
override val nameResolver: NameResolver,
override val typeTable: TypeTable,
override val versionRequirementTable: VersionRequirementTable,
override val containerSource: DeserializedContainerSource?
override val containerSource: DeserializedContainerSource?,
override var isExperimentalCoroutineInReleaseEnvironment: Boolean = false
) : DeserializedCallableMemberDescriptor, PropertyDescriptorImpl(
containingDeclaration, original, annotations, modality, visibility, isVar, name, kind, SourceElement.NO_SOURCE,
isLateInit, isConst, isExpect, false, isExternal, isDelegated
@@ -123,7 +127,8 @@ class DeserializedPropertyDescriptor(
): PropertyDescriptorImpl {
return DeserializedPropertyDescriptor(
newOwner, original, annotations, newModality, newVisibility, isVar, newName, kind, isLateInit, isConst, isExternal,
@Suppress("DEPRECATION") isDelegated, isExpect, proto, nameResolver, typeTable, versionRequirementTable, containerSource
@Suppress("DEPRECATION") isDelegated, isExpect, proto, nameResolver, typeTable, versionRequirementTable, containerSource,
isExperimentalCoroutineInReleaseEnvironment
)
}
@@ -141,7 +146,8 @@ class DeserializedClassConstructorDescriptor(
override val typeTable: TypeTable,
override val versionRequirementTable: VersionRequirementTable,
override val containerSource: DeserializedContainerSource?,
source: SourceElement? = null
source: SourceElement? = null,
override var isExperimentalCoroutineInReleaseEnvironment: Boolean = false
) : DeserializedCallableMemberDescriptor,
ClassConstructorDescriptorImpl(containingDeclaration, original, annotations, isPrimary, kind, source ?: SourceElement.NO_SOURCE) {
@@ -178,7 +184,8 @@ class DeserializedTypeAliasDescriptor(
override val nameResolver: NameResolver,
override val typeTable: TypeTable,
override val versionRequirementTable: VersionRequirementTable,
override val containerSource: DeserializedContainerSource?
override val containerSource: DeserializedContainerSource?,
override var isExperimentalCoroutineInReleaseEnvironment: Boolean = false
) : AbstractTypeAliasDescriptor(containingDeclaration, annotations, name, SourceElement.NO_SOURCE, visibility),
DeserializedMemberDescriptor {
override lateinit var constructors: Collection<TypeAliasConstructorDescriptor> private set
@@ -210,7 +217,8 @@ class DeserializedTypeAliasDescriptor(
if (substitutor.isEmpty) return this
val substituted = DeserializedTypeAliasDescriptor(
storageManager, containingDeclaration, annotations, name, visibility,
proto, nameResolver, typeTable, versionRequirementTable, containerSource
proto, nameResolver, typeTable, versionRequirementTable, containerSource,
isExperimentalCoroutineInReleaseEnvironment
)
substituted.initialize(
declaredTypeParameters,