Fix expect discrimination with actual typealias in deserialization

* For types encountered during deserialization, search for a classifier,
  not necessarily a class, across module dependencies (i.e. accept type
  aliases, returned when actual type alias discriminates an expect
  class).

* When the referenced type is a type alias, expand it, so that when
  the descriptor is compared to the expansion in other places,
  they match.

* Also, when resolving an abbreviation, don't expand the type aliases,
  as there are assumptions in the code base that an abbreviation is a
  type alias.
This commit is contained in:
Sergey Igushkin
2020-04-15 20:59:05 +03:00
parent d4a0844a77
commit 4b0da0688a
2 changed files with 22 additions and 18 deletions
@@ -318,8 +318,8 @@ class MemberDeserializer(private val c: DeserializationContext) {
val local = c.childContext(typeAlias, proto.typeParameterList)
typeAlias.initialize(
local.typeDeserializer.ownTypeParameters,
local.typeDeserializer.simpleType(proto.underlyingType(c.typeTable)),
local.typeDeserializer.simpleType(proto.expandedType(c.typeTable)),
local.typeDeserializer.simpleType(proto.underlyingType(c.typeTable), expandTypeAliases = false),
local.typeDeserializer.simpleType(proto.expandedType(c.typeTable), expandTypeAliases = false),
typeAlias.checkExperimentalCoroutine(local.typeDeserializer)
)
@@ -11,8 +11,6 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedAnnotations
@@ -30,9 +28,10 @@ class TypeDeserializer(
private val containerPresentableName: String,
var experimentalSuspendFunctionTypeEncountered: Boolean = false
) {
private val classDescriptors: (Int) -> ClassDescriptor? = c.storageManager.createMemoizedFunctionWithNullableValues { fqNameIndex ->
computeClassDescriptor(fqNameIndex)
}
private val classifierDescriptors: (Int) -> ClassifierDescriptor? =
c.storageManager.createMemoizedFunctionWithNullableValues { fqNameIndex ->
computeClassifierDescriptor(fqNameIndex)
}
private val typeAliasDescriptors: (Int) -> ClassifierDescriptor? =
c.storageManager.createMemoizedFunctionWithNullableValues { fqNameIndex ->
@@ -62,10 +61,10 @@ class TypeDeserializer(
return c.components.flexibleTypeDeserializer.create(proto, id, lowerBound, upperBound)
}
return simpleType(proto)
return simpleType(proto, expandTypeAliases = true)
}
fun simpleType(proto: ProtoBuf.Type): SimpleType {
fun simpleType(proto: ProtoBuf.Type, expandTypeAliases: Boolean = true): SimpleType {
val localClassifierType = when {
proto.hasClassName() -> computeLocalClassifierReplacementType(proto.className)
proto.hasTypeAliasName() -> computeLocalClassifierReplacementType(proto.typeAliasName)
@@ -90,17 +89,22 @@ class TypeDeserializer(
typeArgument(constructor.parameters.getOrNull(index), argumentProto)
}.toList()
val simpleType = if (Flags.SUSPEND_TYPE.get(proto.flags)) {
createSuspendFunctionType(annotations, constructor, arguments, proto.nullable)
} else {
KotlinTypeFactory.simpleType(annotations, constructor, arguments, proto.nullable)
val declarationDescriptor = constructor.declarationDescriptor
val simpleType = when {
expandTypeAliases && declarationDescriptor is TypeAliasDescriptor ->
with(KotlinTypeFactory) { declarationDescriptor.computeExpandedType(arguments) }
Flags.SUSPEND_TYPE.get(proto.flags) ->
createSuspendFunctionType(annotations, constructor, arguments, proto.nullable)
else ->
KotlinTypeFactory.simpleType(annotations, constructor, arguments, proto.nullable)
}
val computedType = proto.abbreviatedType(c.typeTable)?.let {
simpleType.withAbbreviation(simpleType(it))
// The abbreviation type is expected to be a typealias, and it should not get expanded, we need to keep it
simpleType.withAbbreviation(simpleType(it, expandTypeAliases = false))
} ?: simpleType
if (proto.hasClassName()) {
val classId = c.nameResolver.getClassId(proto.className)
return c.components.platformDependentTypeTransformer.transformPlatformType(classId, computedType)
@@ -121,7 +125,7 @@ class TypeDeserializer(
}
return when {
proto.hasClassName() -> (classDescriptors(proto.className) ?: notFoundClass(proto.className)).typeConstructor
proto.hasClassName() -> (classifierDescriptors(proto.className) ?: notFoundClass(proto.className)).typeConstructor
proto.hasTypeParameter() ->
typeParameterTypeConstructor(proto.typeParameter)
?: ErrorUtils.createErrorTypeConstructor(
@@ -223,13 +227,13 @@ class TypeDeserializer(
private fun typeParameterTypeConstructor(typeParameterId: Int): TypeConstructor? =
typeParameterDescriptors[typeParameterId]?.typeConstructor ?: parent?.typeParameterTypeConstructor(typeParameterId)
private fun computeClassDescriptor(fqNameIndex: Int): ClassDescriptor? {
private fun computeClassifierDescriptor(fqNameIndex: Int): ClassifierDescriptor? {
val id = c.nameResolver.getClassId(fqNameIndex)
if (id.isLocal) {
// Local classes can't be found in scopes
return c.components.deserializeClass(id)
}
return c.components.moduleDescriptor.findClassAcrossModuleDependencies(id)
return c.components.moduleDescriptor.findClassifierAcrossModuleDependencies(id)
}
private fun computeLocalClassifierReplacementType(className: Int): SimpleType? {