From df7b7cf61aabca49312ea7f8230c700d90d79ce3 Mon Sep 17 00:00:00 2001 From: Roman Artemev Date: Fri, 14 Feb 2020 17:46:38 +0300 Subject: [PATCH] [K/N] Provide original class id for forward-declared declarataion --- .../kotlin/types/KotlinTypeFactory.kt | 26 ++++++++++++++ .../deserialization/TypeDeserializer.kt | 34 +++++++++++++++++-- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/KotlinTypeFactory.kt b/core/descriptors/src/org/jetbrains/kotlin/types/KotlinTypeFactory.kt index ed2ce540970..bd3fb390b2e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/KotlinTypeFactory.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/KotlinTypeFactory.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.getRefinedMemberScopeIfPossible import org.jetbrains.kotlin.descriptors.impl.getRefinedUnsubstitutedMemberScopeIfPossible +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor import org.jetbrains.kotlin.resolve.descriptorUtil.getKotlinTypeRefiner import org.jetbrains.kotlin.resolve.descriptorUtil.module @@ -226,6 +227,31 @@ private class SimpleTypeImpl( } } +// Note: a hack to support class descriptor overwriting in case of K/N forward declaration replacement and other such cases +class SupposititiousSimpleType(private val realType: SimpleType, val overwrittenClass: ClassId) : SimpleType() { + + private fun maybeWrap(newType: SimpleType): SupposititiousSimpleType { + return if (newType === realType) this + else SupposititiousSimpleType(newType, overwrittenClass) + } + + override fun replaceAnnotations(newAnnotations: Annotations): SimpleType = + maybeWrap(realType.replaceAnnotations(newAnnotations)) + + override fun makeNullableAsSpecified(newNullability: Boolean): SimpleType = + maybeWrap(realType.makeNullableAsSpecified(newNullability)) + + @TypeRefinement + override fun refine(kotlinTypeRefiner: KotlinTypeRefiner): SimpleType = + maybeWrap(realType.refine(kotlinTypeRefiner)) + + override val constructor: TypeConstructor = realType.constructor + override val arguments: List = realType.arguments + override val isMarkedNullable: Boolean = realType.isMarkedNullable + override val memberScope: MemberScope = realType.memberScope + override val annotations: Annotations = realType.annotations +} + abstract class DelegatingSimpleTypeImpl(override val delegate: SimpleType) : DelegatingSimpleType() { override fun replaceAnnotations(newAnnotations: Annotations) = if (newAnnotations !== annotations) diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt index 08725f00569..4182fa57f71 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt @@ -11,6 +11,8 @@ 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 @@ -94,8 +96,25 @@ class TypeDeserializer( KotlinTypeFactory.simpleType(annotations, constructor, arguments, proto.nullable) } - val abbreviatedTypeProto = proto.abbreviatedType(c.typeTable) ?: return simpleType - return simpleType.withAbbreviation(simpleType(abbreviatedTypeProto)) + val computedType = proto.abbreviatedType(c.typeTable)?.let { + simpleType.withAbbreviation(simpleType(it)) + } ?: simpleType + + // TODO: move this hack in some platform specific place ASAP + if (proto.hasClassName()) { + val classId = c.nameResolver.getClassId(proto.className) + val originalPackageFqn = classId.packageFqName + if (originalPackageFqn in forwardPackagesSet) { + // This hack is about keeping original class id written into proto which is required for correct IR linkage + val classDescriptor = constructor.declarationDescriptor as ClassDescriptor + val realPackageFqn = (classDescriptor.containingDeclaration as PackageFragmentDescriptor).fqName + if (originalPackageFqn != realPackageFqn) { + return SupposititiousSimpleType(computedType, classId) + } + } + } + + return computedType } private fun typeConstructor(proto: ProtoBuf.Type): TypeConstructor { @@ -253,4 +272,15 @@ class TypeDeserializer( } override fun toString() = debugName + (if (parent == null) "" else ". Child of ${parent.debugName}") + + companion object { + private val cNames = FqName("cnames") + private val cNamesStructs = cNames.child(Name.identifier("structs")) + + private val objCNames = FqName("objcnames") + private val objCNamesClasses = objCNames.child(Name.identifier("classes")) + private val objCNamesProtocols = objCNames.child(Name.identifier("protocols")) + + private val forwardPackagesSet = setOf(cNamesStructs, objCNamesClasses, objCNamesProtocols) + } }