[IR] Consider TypeParameter as public declaration and serialize it properly

- Add test case when TypeParameter of generic property is exposed outside its module
This commit is contained in:
Roman Artemev
2019-06-05 14:00:43 +03:00
committed by romanart
parent efaf5a9947
commit 008cf03b06
12 changed files with 129 additions and 43 deletions
@@ -42,7 +42,6 @@ abstract class DeclarationTable(val builtIns: IrBuiltIns, val descriptorTable: D
val index = if (value.origin == IrDeclarationOrigin.FAKE_OVERRIDE ||
!value.isExported()
|| value is IrVariable
|| (value is IrTypeParameter && value.parent !is IrClass)
|| value is IrValueParameter
|| value is IrAnonymousInitializerImpl
) {
@@ -7,10 +7,8 @@ package org.jetbrains.kotlin.backend.common.serialization
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.serialization.UniqIdKey
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.backend.common.serialization.resolveFakeOverrideMaybeAbstract
import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -136,7 +134,18 @@ abstract class DescriptorReferenceDeserializer(
}
if (isTypeParameter) {
return clazz!!.declaredTypeParameters.first { it.name.asString() == name }
for (m in (listOfNotNull(clazz) + members)) {
val typeParameters = when (m) {
is PropertyDescriptor -> m.typeParameters
is ClassDescriptor -> m.declaredTypeParameters
is SimpleFunctionDescriptor -> m.typeParameters
is ClassConstructorDescriptor -> m.typeParameters
else -> emptyList()
}
typeParameters.firstOrNull { it.getUniqId() == index }?.let { return it }
}
}
if (protoIndex?.let { checkIfSpecialDescriptorId(it) } == true) {
@@ -27,11 +27,13 @@ import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.*
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedTypeParameterDescriptor
import org.jetbrains.kotlin.types.Variance
// TODO: This code still has some uses of descriptors:
@@ -823,12 +825,15 @@ abstract class IrModuleDeserializer(
val symbol = deserializeIrSymbol(proto.symbol) as IrTypeParameterSymbol
val name = deserializeName(proto.name)
val variance = deserializeIrTypeVariance(proto.variance)
val descriptor = symbol.descriptor
val parameter = symbolTable.declareGlobalTypeParameter(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
symbol.descriptor
) {
IrTypeParameterImpl(start, end, origin, it, name, proto.index, proto.isReified, variance)
val parameter = if (descriptor is DeserializedTypeParameterDescriptor && descriptor.containingDeclaration is PropertyDescriptor && symbol.isBound) {
// TODO: Get rid of once new properties are implemented
IrTypeParameterImpl(start, end, origin, IrTypeParameterSymbolImpl(descriptor), name, proto.index, proto.isReified, variance)
} else {
symbolTable.declareGlobalTypeParameter(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, descriptor) {
IrTypeParameterImpl(start, end, origin, it, name, proto.index, proto.isReified, variance)
}
}
val superTypes = proto.superTypeList.map { deserializeIrType(it) }
@@ -966,19 +971,20 @@ abstract class IrModuleDeserializer(
val symbol = deserializeIrSymbol(proto.symbol) as IrSimpleFunctionSymbol
val function = symbolTable.declareSimpleFunction(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
symbol.descriptor, {
IrFunctionImpl(
start, end, origin, it,
deserializeName(proto.base.name),
deserializeVisibility(proto.base.visibility),
deserializeModality(proto.modality),
deserializeIrType(proto.base.returnType),
proto.base.isInline,
proto.base.isExternal,
proto.isTailrec,
proto.isSuspend
)
})
symbol.descriptor
) {
IrFunctionImpl(
start, end, origin, it,
deserializeName(proto.base.name),
deserializeVisibility(proto.base.visibility),
deserializeModality(proto.modality),
deserializeIrType(proto.base.returnType),
proto.base.isInline,
proto.base.isExternal,
proto.isTailrec,
proto.isSuspend
)
}
deserializeIrFunctionBase(proto.base, function as IrFunctionBase, start, end, origin)
val overridden = proto.overriddenList.map { deserializeIrSymbol(it) as IrSimpleFunctionSymbol }
@@ -200,8 +200,14 @@ abstract class KotlinManglerImpl: KotlinMangler {
val IrTypeParameter.symbolName: String
get() {
val containingDeclarationPart = parent.fqNameForIrSerialization
return "ktypeparam:$containingDeclarationPart$name"
val parentDeclaration = (parent as? IrSimpleFunction)?.correspondingPropertySymbol?.owner ?: parent
val containingDeclarationPart = when (parentDeclaration) {
is IrDeclarationParent -> parentDeclaration.fqNameUnique.asString()
is IrProperty -> "${parentDeclaration.parent.fqNameUnique}.${parentDeclaration.name}"
else -> error("Unexpected type parameter parent")
}
return "ktypeparam:$containingDeclarationPart$name@$index"
}
// This is a little extension over what's used in real mangling
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.ir.util.isAccessor
import org.jetbrains.kotlin.ir.util.isGetter
import org.jetbrains.kotlin.ir.util.isSetter
import org.jetbrains.kotlin.ir.util.nameForIrSerialization
import org.jetbrains.kotlin.ir.util.nameForIrSerialization
import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
@@ -26,6 +27,21 @@ open class DescriptorReferenceSerializer(
return DescriptorFactory.isEnumValueOfMethod(descriptor) || DescriptorFactory.isEnumValuesMethod(descriptor)
}
fun extractPackageAndClassFqns(descriptor: DeclarationDescriptor): Pair<String, String>? {
val containingDeclaration = descriptor.containingDeclaration
return when (containingDeclaration) {
is ClassDescriptor -> {
val classId = containingDeclaration.classId ?: return null
Pair(classId.packageFqName.toString(), classId.relativeClassName.toString())
}
is PackageFragmentDescriptor -> Pair(containingDeclaration.fqName.toString(), "")
is PropertyDescriptor -> if (descriptor !is TypeParameterDescriptor) null else {
extractPackageAndClassFqns(containingDeclaration)
}
else -> return null
}
}
// Not all exported descriptors are deserialized, some a synthesized anew during metadata deserialization.
// Those created descriptors can't carry the uniqIdIndex, since it is available only for deserialized descriptors.
// So we record the uniq id of some other "discoverable" descriptor for which we know for sure that it will be
@@ -40,21 +56,10 @@ open class DescriptorReferenceSerializer(
}
if (declaration is IrAnonymousInitializer) return null
if (descriptor is ParameterDescriptor ||
(descriptor is VariableDescriptor && descriptor !is PropertyDescriptor)
|| (declaration is IrTypeParameter && declaration.parent !is IrClass)
) return null
if (descriptor is ParameterDescriptor || (descriptor is VariableDescriptor && descriptor !is PropertyDescriptor)) return null
val containingDeclaration = descriptor.containingDeclaration!!
val (packageFqName, classFqName) = when (containingDeclaration) {
is ClassDescriptor -> {
val classId = containingDeclaration.classId ?: return null
Pair(classId.packageFqName.toString(), classId.relativeClassName.toString())
}
is PackageFragmentDescriptor -> Pair(containingDeclaration.fqName.toString(), "")
else -> return null
}
val (packageFqName, classFqName) = extractPackageAndClassFqns(descriptor) ?: return null
val isAccessor = declaration.isAccessor
val isBackingField = declaration is IrField && declaration.correspondingProperty != null
@@ -62,7 +67,7 @@ open class DescriptorReferenceSerializer(
val isDefaultConstructor = descriptor is ClassConstructorDescriptor && containingDeclaration is ClassDescriptor && (containingDeclaration.kind == ClassKind.OBJECT)
val isEnumEntry = descriptor is ClassDescriptor && descriptor.kind == ClassKind.ENUM_ENTRY
val isEnumSpecial = isEnumSpecialMember(descriptor)
val isTypeParameter = declaration is IrTypeParameter && declaration.parent is IrClass
val isTypeParameter = declaration is IrTypeParameter
// The corresponding descriptor in deserialized metadata has constructors = emptyList() etc.
if (containingDeclaration is ClassDescriptor &&
@@ -90,13 +95,24 @@ open class DescriptorReferenceSerializer(
realDeclaration
}
val nameString = if (isTypeParameter) {
val parent = declaration.parent
val typeParameterContainer = when (parent) {
is IrClass -> parent
is IrSimpleFunction -> parent.correspondingPropertySymbol?.owner ?: parent
is IrConstructor -> parent
else -> error("unknown type parameter container type")
}
typeParameterContainer.descriptor.name.asString()
} else descriptor.name.toString()
val uniqId = discoverableDescriptorsDeclaration?.let { declarationTable.uniqIdByDeclaration(it) }
uniqId?.let { declarationTable.descriptors.put(discoverableDescriptorsDeclaration.descriptor, it) }
val proto = KotlinIr.DescriptorReference.newBuilder()
.setPackageFqName(serializeString(packageFqName))
.setClassFqName(serializeString(classFqName))
.setName(serializeString(descriptor.name.toString()))
.setName(serializeString(nameString))
if (uniqId != null) proto.setUniqId(protoUniqId(uniqId))