Add ClassDescriptor.getInlineClassRepresentation

This will be used at least in the JVM backend instead of the current
approach where we're loading the primary constructor's first parameter,
which isn't good enough since primary constructor can be private, and
we can't rely on private declarations in case they're declared in
another module.
This commit is contained in:
Alexander Udalov
2021-03-23 12:58:53 +01:00
parent 6aaff9dfb7
commit 7fb3f48c67
22 changed files with 214 additions and 11 deletions
@@ -15,10 +15,7 @@ import org.jetbrains.kotlin.incremental.record
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.NonReportingOverrideStrategy
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.CliSealedClassInheritorsProvider
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScope
@@ -68,6 +65,7 @@ class DeserializedClassDescriptor(
private val constructors = c.storageManager.createLazyValue { computeConstructors() }
private val companionObjectDescriptor = c.storageManager.createNullableLazyValue { computeCompanionObjectDescriptor() }
private val sealedSubclasses = c.storageManager.createLazyValue { computeSubclassesForSealedClass() }
private val inlineClassRepresentation = c.storageManager.createNullableLazyValue { computeInlineClassRepresentation() }
internal val thisAsProtoContainer: ProtoContainer.Class = ProtoContainer.Class(
classProto, c.nameResolver, c.typeTable, sourceElement,
@@ -170,6 +168,35 @@ class DeserializedClassDescriptor(
override fun getSealedSubclasses() = sealedSubclasses()
override fun getInlineClassRepresentation(): InlineClassRepresentation<SimpleType>? = inlineClassRepresentation()
private fun computeInlineClassRepresentation(): InlineClassRepresentation<SimpleType>? {
if (!isInlineClass()) return null
val propertyName = when {
classProto.hasInlineClassUnderlyingPropertyName() ->
c.nameResolver.getName(classProto.inlineClassUnderlyingPropertyName)
!metadataVersion.isAtLeast(1, 5, 1) -> {
// Before 1.5, inline classes did not have underlying property name & type in the metadata.
// However, they were experimental, so supposedly this logic can be removed at some point in the future.
val constructor = unsubstitutedPrimaryConstructor ?: error("Inline class has no primary constructor: $this")
constructor.valueParameters.first().name
}
else -> error("Inline class has no underlying property name in metadata: $this")
}
val type = classProto.inlineClassUnderlyingType(c.typeTable)?.let(c.typeDeserializer::simpleType)
?: run {
val underlyingProperty =
memberScope.getContributedVariables(propertyName, NoLookupLocation.FROM_DESERIALIZATION)
.singleOrNull { it.extensionReceiverParameter == null }
?: error("Inline class has no underlying property: $this")
underlyingProperty.type as SimpleType
}
return InlineClassRepresentation(propertyName, type)
}
override fun toString() =
"deserialized ${if (isExpect) "expect " else ""}class $name" // not using descriptor renderer to preserve laziness