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) val local = c.childContext(typeAlias, proto.typeParameterList)
typeAlias.initialize( typeAlias.initialize(
local.typeDeserializer.ownTypeParameters, local.typeDeserializer.ownTypeParameters,
local.typeDeserializer.simpleType(proto.underlyingType(c.typeTable)), local.typeDeserializer.simpleType(proto.underlyingType(c.typeTable), expandTypeAliases = false),
local.typeDeserializer.simpleType(proto.expandedType(c.typeTable)), local.typeDeserializer.simpleType(proto.expandedType(c.typeTable), expandTypeAliases = false),
typeAlias.checkExperimentalCoroutine(local.typeDeserializer) 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.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.* import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.name.ClassId 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.fqNameOrNull
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedAnnotations import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedAnnotations
@@ -30,9 +28,10 @@ class TypeDeserializer(
private val containerPresentableName: String, private val containerPresentableName: String,
var experimentalSuspendFunctionTypeEncountered: Boolean = false var experimentalSuspendFunctionTypeEncountered: Boolean = false
) { ) {
private val classDescriptors: (Int) -> ClassDescriptor? = c.storageManager.createMemoizedFunctionWithNullableValues { fqNameIndex -> private val classifierDescriptors: (Int) -> ClassifierDescriptor? =
computeClassDescriptor(fqNameIndex) c.storageManager.createMemoizedFunctionWithNullableValues { fqNameIndex ->
} computeClassifierDescriptor(fqNameIndex)
}
private val typeAliasDescriptors: (Int) -> ClassifierDescriptor? = private val typeAliasDescriptors: (Int) -> ClassifierDescriptor? =
c.storageManager.createMemoizedFunctionWithNullableValues { fqNameIndex -> c.storageManager.createMemoizedFunctionWithNullableValues { fqNameIndex ->
@@ -62,10 +61,10 @@ class TypeDeserializer(
return c.components.flexibleTypeDeserializer.create(proto, id, lowerBound, upperBound) 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 { val localClassifierType = when {
proto.hasClassName() -> computeLocalClassifierReplacementType(proto.className) proto.hasClassName() -> computeLocalClassifierReplacementType(proto.className)
proto.hasTypeAliasName() -> computeLocalClassifierReplacementType(proto.typeAliasName) proto.hasTypeAliasName() -> computeLocalClassifierReplacementType(proto.typeAliasName)
@@ -90,17 +89,22 @@ class TypeDeserializer(
typeArgument(constructor.parameters.getOrNull(index), argumentProto) typeArgument(constructor.parameters.getOrNull(index), argumentProto)
}.toList() }.toList()
val simpleType = if (Flags.SUSPEND_TYPE.get(proto.flags)) { val declarationDescriptor = constructor.declarationDescriptor
createSuspendFunctionType(annotations, constructor, arguments, proto.nullable)
} else { val simpleType = when {
KotlinTypeFactory.simpleType(annotations, constructor, arguments, proto.nullable) 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 { 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 } ?: simpleType
if (proto.hasClassName()) { if (proto.hasClassName()) {
val classId = c.nameResolver.getClassId(proto.className) val classId = c.nameResolver.getClassId(proto.className)
return c.components.platformDependentTypeTransformer.transformPlatformType(classId, computedType) return c.components.platformDependentTypeTransformer.transformPlatformType(classId, computedType)
@@ -121,7 +125,7 @@ class TypeDeserializer(
} }
return when { return when {
proto.hasClassName() -> (classDescriptors(proto.className) ?: notFoundClass(proto.className)).typeConstructor proto.hasClassName() -> (classifierDescriptors(proto.className) ?: notFoundClass(proto.className)).typeConstructor
proto.hasTypeParameter() -> proto.hasTypeParameter() ->
typeParameterTypeConstructor(proto.typeParameter) typeParameterTypeConstructor(proto.typeParameter)
?: ErrorUtils.createErrorTypeConstructor( ?: ErrorUtils.createErrorTypeConstructor(
@@ -223,13 +227,13 @@ class TypeDeserializer(
private fun typeParameterTypeConstructor(typeParameterId: Int): TypeConstructor? = private fun typeParameterTypeConstructor(typeParameterId: Int): TypeConstructor? =
typeParameterDescriptors[typeParameterId]?.typeConstructor ?: parent?.typeParameterTypeConstructor(typeParameterId) typeParameterDescriptors[typeParameterId]?.typeConstructor ?: parent?.typeParameterTypeConstructor(typeParameterId)
private fun computeClassDescriptor(fqNameIndex: Int): ClassDescriptor? { private fun computeClassifierDescriptor(fqNameIndex: Int): ClassifierDescriptor? {
val id = c.nameResolver.getClassId(fqNameIndex) val id = c.nameResolver.getClassId(fqNameIndex)
if (id.isLocal) { if (id.isLocal) {
// Local classes can't be found in scopes // Local classes can't be found in scopes
return c.components.deserializeClass(id) return c.components.deserializeClass(id)
} }
return c.components.moduleDescriptor.findClassAcrossModuleDependencies(id) return c.components.moduleDescriptor.findClassifierAcrossModuleDependencies(id)
} }
private fun computeLocalClassifierReplacementType(className: Int): SimpleType? { private fun computeLocalClassifierReplacementType(className: Int): SimpleType? {