Fix serialization for suspend function types.
Since now `suspend (Int) -> String` will be serialized as `(Int, Continuation<String>) -> Any?` + suspend flag. Before this change such type serialized like this: Function2<Int, String> + suspend flag. And yes, type `Function2<Int, String>` isn't correct, because Function2 expect 3 type arguments. We have special logic for this case and we deserialize such error-written types correctly. (cherry picked from commit 3518cbe)
This commit is contained in:
committed by
Stanislav Erokhin
parent
382122470f
commit
a4272caa8c
+8
-14
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
|
||||
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
|
||||
import org.jetbrains.kotlin.builtins.transformSuspendFunctionToRuntimeFunctionType
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
@@ -451,6 +452,12 @@ class DescriptorSerializer private constructor(
|
||||
return lowerBound
|
||||
}
|
||||
|
||||
if (type.isSuspendFunctionType) {
|
||||
val functionType = type(transformSuspendFunctionToRuntimeFunctionType(type))
|
||||
functionType.flags = Flags.getTypeFlags(true)
|
||||
return functionType
|
||||
}
|
||||
|
||||
val descriptor = type.constructor.declarationDescriptor
|
||||
when (descriptor) {
|
||||
is ClassDescriptor, is TypeAliasDescriptor -> {
|
||||
@@ -489,25 +496,12 @@ class DescriptorSerializer private constructor(
|
||||
}
|
||||
|
||||
private fun fillFromPossiblyInnerType(builder: ProtoBuf.Type.Builder, type: PossiblyInnerType) {
|
||||
val classifierDescriptor: ClassifierDescriptorWithTypeParameters
|
||||
val isSuspendType: Boolean
|
||||
|
||||
val originalClassifierDescriptor = type.classifierDescriptor
|
||||
if (originalClassifierDescriptor.getFunctionalClassKind() == FunctionClassDescriptor.Kind.SuspendFunction) {
|
||||
classifierDescriptor = originalClassifierDescriptor.builtIns.getFunction(originalClassifierDescriptor.declaredTypeParameters.size)
|
||||
isSuspendType = true
|
||||
}
|
||||
else {
|
||||
classifierDescriptor = originalClassifierDescriptor
|
||||
isSuspendType = false
|
||||
}
|
||||
|
||||
val classifierDescriptor = type.classifierDescriptor
|
||||
val classifierId = getClassifierId(classifierDescriptor)
|
||||
when (classifierDescriptor) {
|
||||
is ClassDescriptor -> builder.className = classifierId
|
||||
is TypeAliasDescriptor -> builder.typeAliasName = classifierId
|
||||
}
|
||||
builder.flags = Flags.getTypeFlags(isSuspendType)
|
||||
|
||||
for (projection in type.arguments) {
|
||||
builder.addArgument(typeArgument(projection))
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ class JvmMetadataVersion(vararg numbers: Int) : BinaryVersion(*numbers) {
|
||||
var skipCheck: Boolean = false
|
||||
|
||||
@JvmField
|
||||
val INSTANCE = JvmMetadataVersion(1, 1, 4)
|
||||
val INSTANCE = JvmMetadataVersion(1, 1, 5)
|
||||
|
||||
@JvmField
|
||||
val INVALID_VERSION = JvmMetadataVersion()
|
||||
|
||||
+1
-33
@@ -64,22 +64,6 @@ interface TypeMappingConfiguration<out T : Any> {
|
||||
|
||||
const val NON_EXISTENT_CLASS_NAME = "error/NonExistentClass"
|
||||
|
||||
private val FAKE_CONTINUATION_CLASS_DESCRIPTOR =
|
||||
MutableClassDescriptor(
|
||||
ErrorUtils.getErrorModule(),
|
||||
ClassKind.INTERFACE, /* isInner = */ false, /* isExternal = */ false,
|
||||
DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME.shortName(), SourceElement.NO_SOURCE
|
||||
).apply {
|
||||
modality = Modality.ABSTRACT
|
||||
visibility = Visibilities.PUBLIC
|
||||
setTypeParameterDescriptors(
|
||||
TypeParameterDescriptorImpl.createWithDefaultBound(
|
||||
this, Annotations.EMPTY, false, Variance.IN_VARIANCE, Name.identifier("T"), 0
|
||||
).let(::listOf)
|
||||
)
|
||||
createTypeConstructor()
|
||||
}
|
||||
|
||||
private val CONTINUATION_INTERNAL_NAME =
|
||||
JvmClassName.byClassId(ClassId.topLevel(DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME)).internalName
|
||||
|
||||
@@ -93,23 +77,7 @@ fun <T : Any> mapType(
|
||||
): T {
|
||||
if (kotlinType.isSuspendFunctionType) {
|
||||
return mapType(
|
||||
createFunctionType(
|
||||
kotlinType.builtIns,
|
||||
kotlinType.annotations,
|
||||
kotlinType.getReceiverTypeFromFunctionType(),
|
||||
kotlinType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType) +
|
||||
KotlinTypeFactory.simpleType(
|
||||
Annotations.EMPTY,
|
||||
// Continuation interface is not a part of built-ins anymore, it has been moved to stdlib.
|
||||
// While it must be somewhere in the dependencies, but here we don't have a reference to the module,
|
||||
// and it's rather complicated to inject it by now, so we just use a fake class descriptor.
|
||||
FAKE_CONTINUATION_CLASS_DESCRIPTOR.typeConstructor,
|
||||
listOf(kotlinType.getReturnTypeFromFunctionType().asTypeProjection()), nullable = false
|
||||
),
|
||||
// TODO: names
|
||||
null,
|
||||
kotlinType.builtIns.nullableAnyType
|
||||
),
|
||||
transformSuspendFunctionToRuntimeFunctionType(kotlinType),
|
||||
factory, mode, typeMappingConfiguration, descriptorTypeWriter,
|
||||
writeGenericType
|
||||
)
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.builtins
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.MutableClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
|
||||
|
||||
val FAKE_CONTINUATION_CLASS_DESCRIPTOR =
|
||||
MutableClassDescriptor(
|
||||
EmptyPackageFragmentDescriptor(ErrorUtils.getErrorModule(), DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME),
|
||||
ClassKind.INTERFACE, /* isInner = */ false, /* isExternal = */ false,
|
||||
DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME.shortName(), SourceElement.NO_SOURCE
|
||||
).apply {
|
||||
modality = Modality.ABSTRACT
|
||||
visibility = Visibilities.PUBLIC
|
||||
setTypeParameterDescriptors(
|
||||
TypeParameterDescriptorImpl.createWithDefaultBound(
|
||||
this, Annotations.EMPTY, false, Variance.IN_VARIANCE, Name.identifier("T"), 0
|
||||
).let(::listOf)
|
||||
)
|
||||
createTypeConstructor()
|
||||
}
|
||||
|
||||
|
||||
fun transformSuspendFunctionToRuntimeFunctionType(suspendFunType: KotlinType): SimpleType {
|
||||
assert(suspendFunType.isSuspendFunctionType) {
|
||||
"This type should be suspend function type: $suspendFunType"
|
||||
}
|
||||
|
||||
return createFunctionType(
|
||||
suspendFunType.builtIns,
|
||||
suspendFunType.annotations,
|
||||
suspendFunType.getReceiverTypeFromFunctionType(),
|
||||
suspendFunType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType) +
|
||||
KotlinTypeFactory.simpleType(
|
||||
Annotations.EMPTY,
|
||||
// Continuation interface is not a part of built-ins anymore, it has been moved to stdlib.
|
||||
// While it must be somewhere in the dependencies, but here we don't have a reference to the module,
|
||||
// and it's rather complicated to inject it by now, so we just use a fake class descriptor.
|
||||
FAKE_CONTINUATION_CLASS_DESCRIPTOR.typeConstructor,
|
||||
listOf(suspendFunType.getReturnTypeFromFunctionType().asTypeProjection()), nullable = false
|
||||
),
|
||||
// TODO: names
|
||||
null,
|
||||
suspendFunType.builtIns.nullableAnyType
|
||||
).makeNullableAsSpecified(suspendFunType.isMarkedNullable)
|
||||
}
|
||||
|
||||
fun transformRuntimeFunctionTypeToSuspendFunction(funType: KotlinType): SimpleType? {
|
||||
assert(funType.isFunctionType) {
|
||||
"This type should be function type: $funType"
|
||||
}
|
||||
|
||||
val continuationArgumentType = funType.getValueParameterTypesFromFunctionType().lastOrNull()?.type ?: return null
|
||||
if (continuationArgumentType.constructor.declarationDescriptor?.fqNameSafe != DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME
|
||||
|| continuationArgumentType.arguments.size != 1
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
val suspendReturnType = continuationArgumentType.arguments.single().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)
|
||||
}
|
||||
+35
-18
@@ -16,18 +16,19 @@
|
||||
|
||||
package org.jetbrains.kotlin.serialization.deserialization
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.BuiltInFictitiousFunctionClassFactory
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.builtins.transformRuntimeFunctionTypeToSuspendFunction
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.serialization.Flags
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedAnnotationsWithPossibleTargets
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedTypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||
import org.jetbrains.kotlin.utils.toReadOnlyList
|
||||
import java.util.*
|
||||
|
||||
@@ -99,7 +100,12 @@ class TypeDeserializer(
|
||||
typeArgument(constructor.parameters.getOrNull(index), proto)
|
||||
}.toReadOnlyList()
|
||||
|
||||
val simpleType = KotlinTypeFactory.simpleType(annotations, constructor, arguments, proto.nullable)
|
||||
val simpleType = if (Flags.SUSPEND_TYPE.get(proto.flags)) {
|
||||
createSuspendFunctionType(annotations, constructor, arguments, proto.nullable)
|
||||
}
|
||||
else {
|
||||
KotlinTypeFactory.simpleType(annotations, constructor, arguments, proto.nullable)
|
||||
}
|
||||
|
||||
val abbreviatedTypeProto = proto.abbreviatedType(c.typeTable) ?: return simpleType
|
||||
return simpleType.withAbbreviation(simpleType(abbreviatedTypeProto, additionalAnnotations))
|
||||
@@ -108,13 +114,8 @@ class TypeDeserializer(
|
||||
private fun typeConstructor(proto: ProtoBuf.Type): TypeConstructor =
|
||||
when {
|
||||
proto.hasClassName() -> {
|
||||
if (Flags.SUSPEND_TYPE.get(proto.flags)) {
|
||||
getSuspendFunctionTypeConstructor(proto)
|
||||
}
|
||||
else {
|
||||
classDescriptors(proto.className)?.typeConstructor
|
||||
?: c.components.notFoundClasses.getClass(proto, c.nameResolver, c.typeTable)
|
||||
}
|
||||
classDescriptors(proto.className)?.typeConstructor
|
||||
?: c.components.notFoundClasses.getClass(proto, c.nameResolver, c.typeTable)
|
||||
}
|
||||
proto.hasTypeParameter() ->
|
||||
typeParameterTypeConstructor(proto.typeParameter)
|
||||
@@ -132,14 +133,30 @@ class TypeDeserializer(
|
||||
else -> ErrorUtils.createErrorTypeConstructor("Unknown type")
|
||||
}
|
||||
|
||||
private fun getSuspendFunctionTypeConstructor(proto: ProtoBuf.Type): TypeConstructor {
|
||||
val classId = c.nameResolver.getClassId(proto.className)
|
||||
val arity = BuiltInFictitiousFunctionClassFactory.getFunctionalClassArity(classId.shortClassName.asString(), classId.packageFqName)
|
||||
|
||||
return if (arity != null)
|
||||
c.containingDeclaration.builtIns.getSuspendFunction(arity - 1).typeConstructor
|
||||
else
|
||||
ErrorUtils.createErrorTypeConstructor("Class is not a FunctionN ${classId.asString()}")
|
||||
private fun createSuspendFunctionType(
|
||||
annotations: Annotations,
|
||||
functionTypeConstructor: TypeConstructor,
|
||||
arguments: List<TypeProjection>,
|
||||
nullable: Boolean
|
||||
): SimpleType {
|
||||
val result = when (functionTypeConstructor.parameters.size - arguments.size) {
|
||||
0 -> {
|
||||
val functionType = KotlinTypeFactory.simpleType(annotations, functionTypeConstructor, arguments, nullable)
|
||||
functionType.check { it.isFunctionType }?.let(::transformRuntimeFunctionTypeToSuspendFunction)
|
||||
}
|
||||
// This case for types written by eap compiler 1.1
|
||||
1 -> {
|
||||
val arity = arguments.size - 1
|
||||
if (arity > 0) {
|
||||
KotlinTypeFactory.simpleType(annotations, functionTypeConstructor.builtIns.getSuspendFunction(arity).typeConstructor, arguments, nullable)
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
return result ?: ErrorUtils.createErrorTypeWithArguments("Bad suspend function in metadata with constructor: $functionTypeConstructor", arguments)
|
||||
}
|
||||
|
||||
private fun typeParameterTypeConstructor(typeParameterId: Int): TypeConstructor? =
|
||||
|
||||
Reference in New Issue
Block a user