[FIR] Introduce valueClassRepresentation to FIR

#KT-1179
This commit is contained in:
Evgeniy.Zhelenskiy
2022-03-14 16:33:05 +03:00
committed by teamcity
parent 28bf83ceac
commit b6f2513dd2
16 changed files with 131 additions and 33 deletions
@@ -6,19 +6,13 @@
package org.jetbrains.kotlin.fir.deserialization
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltInsSignatures
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.*
import org.jetbrains.kotlin.fir.declarations.comparators.FirMemberDeclarationComparator
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.utils.addDeclarations
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
import org.jetbrains.kotlin.fir.declarations.utils.moduleName
import org.jetbrains.kotlin.fir.declarations.utils.sourceElement
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.scopes.FirScopeProvider
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
@@ -26,8 +20,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.symbols.impl.FirEnumEntrySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.ConeAttributes
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
@@ -208,6 +201,9 @@ fun deserializeClassToSymbol(
}
it.setSealedClassInheritors(inheritors)
}
it.valueClassRepresentation = computeValueClassRepresentation(it, session)
(it.annotations as MutableList<FirAnnotation>) +=
context.annotationDeserializer.loadClassAnnotations(classProto, context.nameResolver)
@@ -172,18 +172,18 @@ class FirElementSerializer private constructor(
builder.companionObjectName = getSimpleNameIndex(companionObject.name)
}
val representation = (klass as? FirRegularClass)?.getInlineClassUnderlyingParameter(session)
val representation = (klass as? FirRegularClass)?.inlineClassRepresentation
if (representation != null) {
builder.inlineClassUnderlyingPropertyName = getSimpleNameIndex(representation.name)
builder.inlineClassUnderlyingPropertyName = getSimpleNameIndex(representation.underlyingPropertyName)
val property = callableMembers.single {
it is FirProperty && it.receiverTypeRef == null && it.name == representation.name
it is FirProperty && it.receiverTypeRef == null && it.name == representation.underlyingPropertyName
}
if (!property.visibility.isPublicAPI) {
if (useTypeTable()) {
builder.inlineClassUnderlyingTypeId = typeId(representation.returnTypeRef)
builder.inlineClassUnderlyingTypeId = typeId(representation.underlyingType)
} else {
builder.setInlineClassUnderlyingType(typeProto(representation.returnTypeRef))
builder.setInlineClassUnderlyingType(typeProto(representation.underlyingType))
}
}
}
@@ -643,14 +643,13 @@ fun Fir2IrComponents.createTemporaryVariableForSafeCallConstruction(
): Pair<IrVariable, IrValueSymbol> =
createTemporaryVariable(receiverExpression, conversionScope, "safe_receiver")
// TODO: implement valueClassRepresentation in FirRegularClass instead. zhelenskiy
fun Fir2IrComponents.computeValueClassRepresentation(klass: FirRegularClass): ValueClassRepresentation<IrSimpleType>? {
val parameters = klass.getValueClassUnderlyingParameters(session) ?: return null
return createValueClassRepresentation(IrTypeSystemContextImpl(irBuiltIns), parameters.map {
val type = it.returnTypeRef.toIrType(typeConverter).safeAs<IrSimpleType>()
?: error("Value class underlying type is not a simple type: ${klass.render()}")
it.name to type
})
require((klass.valueClassRepresentation != null) == klass.isInline)
return klass.valueClassRepresentation?.mapUnderlyingType {
with(typeConverter) {
it.toIrType() as? IrSimpleType?: error("Value class underlying type is not a simple type: ${klass.render()}")
}
}
}
fun FirRegularClass.getIrSymbolsForSealedSubclasses(components: Fir2IrComponents): List<IrClassSymbol> {
@@ -0,0 +1,71 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.declarations
import org.jetbrains.kotlin.descriptors.InlineClassRepresentation
import org.jetbrains.kotlin.descriptors.ValueClassRepresentation
import org.jetbrains.kotlin.descriptors.createValueClassRepresentation
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.utils.isInline
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.substitution.createTypeSubstitutorByTypeConstructor
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.ensureResolved
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.model.typeConstructor
internal fun ConeKotlinType.substitutedUnderlyingTypeForInlineClass(session: FirSession, context: ConeTypeContext): ConeKotlinType? {
val unsubstitutedType = unsubstitutedUnderlyingTypeForInlineClass(session) ?: return null
val substitutor = createTypeSubstitutorByTypeConstructor(
mapOf(this.typeConstructor(context) to this), context, approximateIntegerLiterals = true
)
return substitutor.substituteOrNull(unsubstitutedType)
}
internal fun ConeKotlinType.unsubstitutedUnderlyingTypeForInlineClass(session: FirSession): ConeKotlinType? {
val symbol = (this.fullyExpandedType(session) as? ConeLookupTagBasedType)
?.lookupTag
?.toSymbol(session) as? FirRegularClassSymbol
?: return null
symbol.ensureResolved(FirResolvePhase.STATUS)
return symbol.fir.inlineClassRepresentation?.underlyingType
}
fun computeValueClassRepresentation(klass: FirRegularClass, session: FirSession): ValueClassRepresentation<ConeSimpleKotlinType>? {
val parameters = klass.getValueClassUnderlyingParameters(session)?.takeIf { it.isNotEmpty() } ?: return null
val fields = parameters.map { it.name to it.returnTypeRef.coneType as ConeSimpleKotlinType }
fields.singleOrNull()?.let { (name, type) ->
if (isRecursiveSingleFieldValueClass(type, session, mutableSetOf(type))) { // escape stack overflow
return InlineClassRepresentation(name, type)
}
}
return createValueClassRepresentation(session.typeContext, fields)
}
private fun FirRegularClass.getValueClassUnderlyingParameters(session: FirSession): List<FirValueParameter>? =
if (isInline) primaryConstructorIfAny(session)?.fir?.valueParameters else null
private fun isRecursiveSingleFieldValueClass(
type: ConeSimpleKotlinType,
session: FirSession,
visited: MutableSet<ConeSimpleKotlinType>
): Boolean {
val nextType = type.valueClassRepresentationTypeMarkersList(session)?.singleOrNull()?.second ?: return false
return !visited.add(nextType) || isRecursiveSingleFieldValueClass(nextType, session, visited)
}
private fun ConeSimpleKotlinType.valueClassRepresentationTypeMarkersList(session: FirSession): List<Pair<Name, ConeSimpleKotlinType>>? {
val symbol = this.toSymbol(session) as? FirRegularClassSymbol ?: return null
if (!symbol.fir.isInline) return null
symbol.fir.valueClassRepresentation?.let { return it.underlyingPropertyNamesToTypes }
symbol.ensureResolved(FirResolvePhase.TYPES)
val constructorSymbol = symbol.fir.primaryConstructorIfAny(session) ?: return null
return constructorSymbol.valueParameterSymbols
.onEach { it.ensureResolved(FirResolvePhase.TYPES) }
.map { it.name to it.resolvedReturnType as ConeSimpleKotlinType }
}
@@ -112,6 +112,9 @@ open class FirStatusResolveTransformer(
*/
if (computationStatus != StatusComputationSession.StatusComputationStatus.Computed) {
regularClass.transformStatus(this, statusResolver.resolveStatus(regularClass, containingClass, isLocal = false))
if (regularClass.status.isInline) {
regularClass.valueClassRepresentation = computeValueClassRepresentation(regularClass, session)
}
}
return transformClass(regularClass, data).also {
statusComputationSession.endComputing(regularClass)
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.declarations
import org.jetbrains.kotlin.descriptors.InlineClassRepresentation
import org.jetbrains.kotlin.descriptors.MultiFieldValueClassRepresentation
import org.jetbrains.kotlin.descriptors.ValueClassRepresentation
import org.jetbrains.kotlin.fir.types.ConeSimpleKotlinType
private object FirValueClassRepresentationKey : FirDeclarationDataKey()
var FirRegularClass.valueClassRepresentation: ValueClassRepresentation<ConeSimpleKotlinType>?
by FirDeclarationDataRegistry.data(FirValueClassRepresentationKey)
val FirRegularClass.inlineClassRepresentation: InlineClassRepresentation<ConeSimpleKotlinType>?
get() = valueClassRepresentation as? InlineClassRepresentation<ConeSimpleKotlinType>
val FirRegularClass.multiFieldValueClassRepresentation: MultiFieldValueClassRepresentation<ConeSimpleKotlinType>?
get() = valueClassRepresentation as? MultiFieldValueClassRepresentation<ConeSimpleKotlinType>
@@ -40,12 +40,6 @@ abstract class IrClass :
abstract var valueClassRepresentation: ValueClassRepresentation<IrSimpleType>?
val inlineClassRepresentation: InlineClassRepresentation<IrSimpleType>?
get() = valueClassRepresentation as? InlineClassRepresentation<IrSimpleType>
val multiFieldValueClassRepresentation: MultiFieldValueClassRepresentation<IrSimpleType>?
get() = valueClassRepresentation as? MultiFieldValueClassRepresentation<IrSimpleType>
abstract var sealedSubclasses: List<IrClassSymbol>
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.MultiFieldValueClassRepresentation
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
import org.jetbrains.kotlin.ir.types.IrSimpleType
import java.io.File
fun <D : IrAttributeContainer> D.copyAttributes(other: IrAttributeContainer?): D = apply {
@@ -55,3 +56,10 @@ val IrFunction.isStaticMethodOfClass: Boolean
val IrFunction.isPropertyAccessor: Boolean
get() = this is IrSimpleFunction && correspondingPropertySymbol != null
val IrClass.multiFieldValueClassRepresentation: MultiFieldValueClassRepresentation<IrSimpleType>?
get() = valueClassRepresentation as? MultiFieldValueClassRepresentation<IrSimpleType>
val IrClass.inlineClassRepresentation: InlineClassRepresentation<IrSimpleType>?
get() = valueClassRepresentation as? InlineClassRepresentation<IrSimpleType>
@@ -465,7 +465,7 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
override fun TypeConstructorMarker.isMultiFieldValueClass(): Boolean =
(this as? IrClassSymbol)?.owner?.isMultiFieldValueClass == true
override fun TypeConstructorMarker.valueClassRepresentationTypeMarkersList(): List<Pair<Name, SimpleTypeMarker>>? =
override fun TypeConstructorMarker.getValueClassProperties(): List<Pair<Name, SimpleTypeMarker>>? =
(this as? IrClassSymbol)?.owner?.valueClassRepresentation?.underlyingPropertyNamesToTypes
override fun TypeConstructorMarker.isInnerClass(): Boolean =
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.inlineClassRepresentation
import org.jetbrains.kotlin.ir.types.IrSimpleType
fun getInlineClassUnderlyingType(irClass: IrClass): IrSimpleType {
@@ -18,5 +18,5 @@ class InlineClassRepresentation<Type : SimpleTypeMarker> constructor(
override fun containsPropertyWithName(name: Name): Boolean = underlyingPropertyName == name
override fun propertyTypeByName(name: Name): Type? = underlyingType.takeIf { containsPropertyWithName(name) }
override fun getPropertyTypeByName(name: Name): Type? = underlyingType.takeIf { containsPropertyWithName(name) }
}
@@ -17,5 +17,5 @@ class MultiFieldValueClassRepresentation<Type : SimpleTypeMarker>(
}
override fun containsPropertyWithName(name: Name): Boolean = name in map
override fun propertyTypeByName(name: Name): Type? = map[name]
override fun getPropertyTypeByName(name: Name): Type? = map[name]
}
@@ -32,7 +32,7 @@ interface TypeSystemCommonBackendContext : TypeSystemContext {
fun TypeConstructorMarker.isInlineClass(): Boolean
fun TypeConstructorMarker.isMultiFieldValueClass(): Boolean
fun TypeConstructorMarker.valueClassRepresentationTypeMarkersList(): List<Pair<Name, SimpleTypeMarker>>?
fun TypeConstructorMarker.getValueClassProperties(): List<Pair<Name, SimpleTypeMarker>>?
fun TypeConstructorMarker.isInnerClass(): Boolean
fun TypeParameterMarker.getRepresentativeUpperBound(): KotlinTypeMarker
fun KotlinTypeMarker.getUnsubstitutedUnderlyingType(): KotlinTypeMarker?
@@ -749,7 +749,7 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy
return (declarationDescriptor as? ClassDescriptor)?.valueClassRepresentation is MultiFieldValueClassRepresentation
}
override fun TypeConstructorMarker.valueClassRepresentationTypeMarkersList(): List<Pair<Name, SimpleTypeMarker>>? {
override fun TypeConstructorMarker.getValueClassProperties(): List<Pair<Name, SimpleTypeMarker>>? {
require(this is TypeConstructor, this::errorMessage)
return (declarationDescriptor as? ClassDescriptor)?.valueClassRepresentation?.underlyingPropertyNamesToTypes
}
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.inlineClassRepresentation
import org.jetbrains.kotlin.ir.declarations.isSingleFieldValueClass
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.backend.jvm.ir.psiElement
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.declarations.inlineClassRepresentation
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.parcelize.ParcelizeNames.RAW_VALUE_ANNOTATION_FQ_NAMES