Skip to content

Commit a4272ca

Browse files
committed
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)
1 parent 3821224 commit a4272ca

File tree

5 files changed

+145
-66
lines changed

5 files changed

+145
-66
lines changed

compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
2020
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
2121
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
2222
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
23+
import org.jetbrains.kotlin.builtins.transformSuspendFunctionToRuntimeFunctionType
2324
import org.jetbrains.kotlin.config.LanguageFeature
2425
import org.jetbrains.kotlin.descriptors.*
2526
import org.jetbrains.kotlin.descriptors.annotations.Annotated
@@ -451,6 +452,12 @@ class DescriptorSerializer private constructor(
451452
return lowerBound
452453
}
453454

455+
if (type.isSuspendFunctionType) {
456+
val functionType = type(transformSuspendFunctionToRuntimeFunctionType(type))
457+
functionType.flags = Flags.getTypeFlags(true)
458+
return functionType
459+
}
460+
454461
val descriptor = type.constructor.declarationDescriptor
455462
when (descriptor) {
456463
is ClassDescriptor, is TypeAliasDescriptor -> {
@@ -489,25 +496,12 @@ class DescriptorSerializer private constructor(
489496
}
490497

491498
private fun fillFromPossiblyInnerType(builder: ProtoBuf.Type.Builder, type: PossiblyInnerType) {
492-
val classifierDescriptor: ClassifierDescriptorWithTypeParameters
493-
val isSuspendType: Boolean
494-
495-
val originalClassifierDescriptor = type.classifierDescriptor
496-
if (originalClassifierDescriptor.getFunctionalClassKind() == FunctionClassDescriptor.Kind.SuspendFunction) {
497-
classifierDescriptor = originalClassifierDescriptor.builtIns.getFunction(originalClassifierDescriptor.declaredTypeParameters.size)
498-
isSuspendType = true
499-
}
500-
else {
501-
classifierDescriptor = originalClassifierDescriptor
502-
isSuspendType = false
503-
}
504-
499+
val classifierDescriptor = type.classifierDescriptor
505500
val classifierId = getClassifierId(classifierDescriptor)
506501
when (classifierDescriptor) {
507502
is ClassDescriptor -> builder.className = classifierId
508503
is TypeAliasDescriptor -> builder.typeAliasName = classifierId
509504
}
510-
builder.flags = Flags.getTypeFlags(isSuspendType)
511505

512506
for (projection in type.arguments) {
513507
builder.addArgument(typeArgument(projection))

core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmMetadataVersion.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class JvmMetadataVersion(vararg numbers: Int) : BinaryVersion(*numbers) {
3232
var skipCheck: Boolean = false
3333

3434
@JvmField
35-
val INSTANCE = JvmMetadataVersion(1, 1, 4)
35+
val INSTANCE = JvmMetadataVersion(1, 1, 5)
3636

3737
@JvmField
3838
val INVALID_VERSION = JvmMetadataVersion()

core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/typeSignatureMapping.kt

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -64,22 +64,6 @@ interface TypeMappingConfiguration<out T : Any> {
6464

6565
const val NON_EXISTENT_CLASS_NAME = "error/NonExistentClass"
6666

67-
private val FAKE_CONTINUATION_CLASS_DESCRIPTOR =
68-
MutableClassDescriptor(
69-
ErrorUtils.getErrorModule(),
70-
ClassKind.INTERFACE, /* isInner = */ false, /* isExternal = */ false,
71-
DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME.shortName(), SourceElement.NO_SOURCE
72-
).apply {
73-
modality = Modality.ABSTRACT
74-
visibility = Visibilities.PUBLIC
75-
setTypeParameterDescriptors(
76-
TypeParameterDescriptorImpl.createWithDefaultBound(
77-
this, Annotations.EMPTY, false, Variance.IN_VARIANCE, Name.identifier("T"), 0
78-
).let(::listOf)
79-
)
80-
createTypeConstructor()
81-
}
82-
8367
private val CONTINUATION_INTERNAL_NAME =
8468
JvmClassName.byClassId(ClassId.topLevel(DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME)).internalName
8569

@@ -93,23 +77,7 @@ fun <T : Any> mapType(
9377
): T {
9478
if (kotlinType.isSuspendFunctionType) {
9579
return mapType(
96-
createFunctionType(
97-
kotlinType.builtIns,
98-
kotlinType.annotations,
99-
kotlinType.getReceiverTypeFromFunctionType(),
100-
kotlinType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType) +
101-
KotlinTypeFactory.simpleType(
102-
Annotations.EMPTY,
103-
// Continuation interface is not a part of built-ins anymore, it has been moved to stdlib.
104-
// While it must be somewhere in the dependencies, but here we don't have a reference to the module,
105-
// and it's rather complicated to inject it by now, so we just use a fake class descriptor.
106-
FAKE_CONTINUATION_CLASS_DESCRIPTOR.typeConstructor,
107-
listOf(kotlinType.getReturnTypeFromFunctionType().asTypeProjection()), nullable = false
108-
),
109-
// TODO: names
110-
null,
111-
kotlinType.builtIns.nullableAnyType
112-
),
80+
transformSuspendFunctionToRuntimeFunctionType(kotlinType),
11381
factory, mode, typeMappingConfiguration, descriptorTypeWriter,
11482
writeGenericType
11583
)
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright 2010-2017 JetBrains s.r.o.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.jetbrains.kotlin.builtins
18+
19+
import org.jetbrains.kotlin.descriptors.ClassKind
20+
import org.jetbrains.kotlin.descriptors.Modality
21+
import org.jetbrains.kotlin.descriptors.SourceElement
22+
import org.jetbrains.kotlin.descriptors.Visibilities
23+
import org.jetbrains.kotlin.descriptors.annotations.Annotations
24+
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
25+
import org.jetbrains.kotlin.descriptors.impl.MutableClassDescriptor
26+
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
27+
import org.jetbrains.kotlin.name.Name
28+
import org.jetbrains.kotlin.resolve.DescriptorUtils
29+
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
30+
import org.jetbrains.kotlin.types.*
31+
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
32+
import org.jetbrains.kotlin.types.typeUtil.builtIns
33+
34+
35+
val FAKE_CONTINUATION_CLASS_DESCRIPTOR =
36+
MutableClassDescriptor(
37+
EmptyPackageFragmentDescriptor(ErrorUtils.getErrorModule(), DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME),
38+
ClassKind.INTERFACE, /* isInner = */ false, /* isExternal = */ false,
39+
DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME.shortName(), SourceElement.NO_SOURCE
40+
).apply {
41+
modality = Modality.ABSTRACT
42+
visibility = Visibilities.PUBLIC
43+
setTypeParameterDescriptors(
44+
TypeParameterDescriptorImpl.createWithDefaultBound(
45+
this, Annotations.EMPTY, false, Variance.IN_VARIANCE, Name.identifier("T"), 0
46+
).let(::listOf)
47+
)
48+
createTypeConstructor()
49+
}
50+
51+
52+
fun transformSuspendFunctionToRuntimeFunctionType(suspendFunType: KotlinType): SimpleType {
53+
assert(suspendFunType.isSuspendFunctionType) {
54+
"This type should be suspend function type: $suspendFunType"
55+
}
56+
57+
return createFunctionType(
58+
suspendFunType.builtIns,
59+
suspendFunType.annotations,
60+
suspendFunType.getReceiverTypeFromFunctionType(),
61+
suspendFunType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType) +
62+
KotlinTypeFactory.simpleType(
63+
Annotations.EMPTY,
64+
// Continuation interface is not a part of built-ins anymore, it has been moved to stdlib.
65+
// While it must be somewhere in the dependencies, but here we don't have a reference to the module,
66+
// and it's rather complicated to inject it by now, so we just use a fake class descriptor.
67+
FAKE_CONTINUATION_CLASS_DESCRIPTOR.typeConstructor,
68+
listOf(suspendFunType.getReturnTypeFromFunctionType().asTypeProjection()), nullable = false
69+
),
70+
// TODO: names
71+
null,
72+
suspendFunType.builtIns.nullableAnyType
73+
).makeNullableAsSpecified(suspendFunType.isMarkedNullable)
74+
}
75+
76+
fun transformRuntimeFunctionTypeToSuspendFunction(funType: KotlinType): SimpleType? {
77+
assert(funType.isFunctionType) {
78+
"This type should be function type: $funType"
79+
}
80+
81+
val continuationArgumentType = funType.getValueParameterTypesFromFunctionType().lastOrNull()?.type ?: return null
82+
if (continuationArgumentType.constructor.declarationDescriptor?.fqNameSafe != DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME
83+
|| continuationArgumentType.arguments.size != 1
84+
) {
85+
return null
86+
}
87+
88+
val suspendReturnType = continuationArgumentType.arguments.single().type
89+
90+
return createFunctionType(
91+
funType.builtIns,
92+
funType.annotations,
93+
funType.getReceiverTypeFromFunctionType(),
94+
funType.getValueParameterTypesFromFunctionType().dropLast(1).map(TypeProjection::getType),
95+
// TODO: names
96+
null,
97+
suspendReturnType,
98+
suspendFunction = true
99+
).makeNullableAsSpecified(funType.isMarkedNullable)
100+
}

core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,19 @@
1616

1717
package org.jetbrains.kotlin.serialization.deserialization
1818

19-
import org.jetbrains.kotlin.builtins.functions.BuiltInFictitiousFunctionClassFactory
19+
import org.jetbrains.kotlin.builtins.isFunctionType
20+
import org.jetbrains.kotlin.builtins.transformRuntimeFunctionTypeToSuspendFunction
2021
import org.jetbrains.kotlin.descriptors.ClassDescriptor
2122
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
2223
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
2324
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
2425
import org.jetbrains.kotlin.descriptors.annotations.Annotations
25-
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
2626
import org.jetbrains.kotlin.serialization.Flags
2727
import org.jetbrains.kotlin.serialization.ProtoBuf
2828
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedAnnotationsWithPossibleTargets
2929
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedTypeParameterDescriptor
3030
import org.jetbrains.kotlin.types.*
31+
import org.jetbrains.kotlin.utils.addToStdlib.check
3132
import org.jetbrains.kotlin.utils.toReadOnlyList
3233
import java.util.*
3334

@@ -99,7 +100,12 @@ class TypeDeserializer(
99100
typeArgument(constructor.parameters.getOrNull(index), proto)
100101
}.toReadOnlyList()
101102

102-
val simpleType = KotlinTypeFactory.simpleType(annotations, constructor, arguments, proto.nullable)
103+
val simpleType = if (Flags.SUSPEND_TYPE.get(proto.flags)) {
104+
createSuspendFunctionType(annotations, constructor, arguments, proto.nullable)
105+
}
106+
else {
107+
KotlinTypeFactory.simpleType(annotations, constructor, arguments, proto.nullable)
108+
}
103109

104110
val abbreviatedTypeProto = proto.abbreviatedType(c.typeTable) ?: return simpleType
105111
return simpleType.withAbbreviation(simpleType(abbreviatedTypeProto, additionalAnnotations))
@@ -108,13 +114,8 @@ class TypeDeserializer(
108114
private fun typeConstructor(proto: ProtoBuf.Type): TypeConstructor =
109115
when {
110116
proto.hasClassName() -> {
111-
if (Flags.SUSPEND_TYPE.get(proto.flags)) {
112-
getSuspendFunctionTypeConstructor(proto)
113-
}
114-
else {
115-
classDescriptors(proto.className)?.typeConstructor
116-
?: c.components.notFoundClasses.getClass(proto, c.nameResolver, c.typeTable)
117-
}
117+
classDescriptors(proto.className)?.typeConstructor
118+
?: c.components.notFoundClasses.getClass(proto, c.nameResolver, c.typeTable)
118119
}
119120
proto.hasTypeParameter() ->
120121
typeParameterTypeConstructor(proto.typeParameter)
@@ -132,14 +133,30 @@ class TypeDeserializer(
132133
else -> ErrorUtils.createErrorTypeConstructor("Unknown type")
133134
}
134135

135-
private fun getSuspendFunctionTypeConstructor(proto: ProtoBuf.Type): TypeConstructor {
136-
val classId = c.nameResolver.getClassId(proto.className)
137-
val arity = BuiltInFictitiousFunctionClassFactory.getFunctionalClassArity(classId.shortClassName.asString(), classId.packageFqName)
138-
139-
return if (arity != null)
140-
c.containingDeclaration.builtIns.getSuspendFunction(arity - 1).typeConstructor
141-
else
142-
ErrorUtils.createErrorTypeConstructor("Class is not a FunctionN ${classId.asString()}")
136+
private fun createSuspendFunctionType(
137+
annotations: Annotations,
138+
functionTypeConstructor: TypeConstructor,
139+
arguments: List<TypeProjection>,
140+
nullable: Boolean
141+
): SimpleType {
142+
val result = when (functionTypeConstructor.parameters.size - arguments.size) {
143+
0 -> {
144+
val functionType = KotlinTypeFactory.simpleType(annotations, functionTypeConstructor, arguments, nullable)
145+
functionType.check { it.isFunctionType }?.let(::transformRuntimeFunctionTypeToSuspendFunction)
146+
}
147+
// This case for types written by eap compiler 1.1
148+
1 -> {
149+
val arity = arguments.size - 1
150+
if (arity > 0) {
151+
KotlinTypeFactory.simpleType(annotations, functionTypeConstructor.builtIns.getSuspendFunction(arity).typeConstructor, arguments, nullable)
152+
}
153+
else {
154+
null
155+
}
156+
}
157+
else -> null
158+
}
159+
return result ?: ErrorUtils.createErrorTypeWithArguments("Bad suspend function in metadata with constructor: $functionTypeConstructor", arguments)
143160
}
144161

145162
private fun typeParameterTypeConstructor(typeParameterId: Int): TypeConstructor? =

0 commit comments

Comments
 (0)