diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt index 150a92a43ea..0fc46e1067b 100644 --- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt +++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt @@ -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) += context.annotationDeserializer.loadClassAnnotations(classProto, context.nameResolver) diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt index d360a5146e4..92facff550a 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt @@ -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)) } } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt index 770f55f618f..e6421ec0d90 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt @@ -643,14 +643,13 @@ fun Fir2IrComponents.createTemporaryVariableForSafeCallConstruction( ): Pair = createTemporaryVariable(receiverExpression, conversionScope, "safe_receiver") -// TODO: implement valueClassRepresentation in FirRegularClass instead. zhelenskiy fun Fir2IrComponents.computeValueClassRepresentation(klass: FirRegularClass): ValueClassRepresentation? { - val parameters = klass.getValueClassUnderlyingParameters(session) ?: return null - return createValueClassRepresentation(IrTypeSystemContextImpl(irBuiltIns), parameters.map { - val type = it.returnTypeRef.toIrType(typeConverter).safeAs() - ?: 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 { diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt new file mode 100644 index 00000000000..14589619c92 --- /dev/null +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt @@ -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? { + 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? = + if (isInline) primaryConstructorIfAny(session)?.fir?.valueParameters else null + +private fun isRecursiveSingleFieldValueClass( + type: ConeSimpleKotlinType, + session: FirSession, + visited: MutableSet +): 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>? { + 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 } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt index 968eab1772b..cde40ecb852 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt @@ -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) diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirValueClassRepresentation.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirValueClassRepresentation.kt new file mode 100644 index 00000000000..afbe7dbdad3 --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirValueClassRepresentation.kt @@ -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? + by FirDeclarationDataRegistry.data(FirValueClassRepresentationKey) + +val FirRegularClass.inlineClassRepresentation: InlineClassRepresentation? + get() = valueClassRepresentation as? InlineClassRepresentation + +val FirRegularClass.multiFieldValueClassRepresentation: MultiFieldValueClassRepresentation? + get() = valueClassRepresentation as? MultiFieldValueClassRepresentation + + diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrClass.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrClass.kt index 87c0b4b7858..0198982dfeb 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrClass.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrClass.kt @@ -40,12 +40,6 @@ abstract class IrClass : abstract var valueClassRepresentation: ValueClassRepresentation? - val inlineClassRepresentation: InlineClassRepresentation? - get() = valueClassRepresentation as? InlineClassRepresentation - - val multiFieldValueClassRepresentation: MultiFieldValueClassRepresentation? - get() = valueClassRepresentation as? MultiFieldValueClassRepresentation - abstract var sealedSubclasses: List override fun accept(visitor: IrElementVisitor, data: D): R = diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarations.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarations.kt index 91aba0aba8c..baf30711889 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarations.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarations.kt @@ -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.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? + get() = valueClassRepresentation as? MultiFieldValueClassRepresentation + +val IrClass.inlineClassRepresentation: InlineClassRepresentation? + get() = valueClassRepresentation as? InlineClassRepresentation diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt index b862b5d3f14..4785e31bee6 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt @@ -465,7 +465,7 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon override fun TypeConstructorMarker.isMultiFieldValueClass(): Boolean = (this as? IrClassSymbol)?.owner?.isMultiFieldValueClass == true - override fun TypeConstructorMarker.valueClassRepresentationTypeMarkersList(): List>? = + override fun TypeConstructorMarker.getValueClassProperties(): List>? = (this as? IrClassSymbol)?.owner?.valueClassRepresentation?.underlyingPropertyNamesToTypes override fun TypeConstructorMarker.isInnerClass(): Boolean = diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt index 1435ee5d6b5..91479a378e6 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt @@ -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 { diff --git a/core/compiler.common/src/org/jetbrains/kotlin/descriptors/InlineClassRepresentation.kt b/core/compiler.common/src/org/jetbrains/kotlin/descriptors/InlineClassRepresentation.kt index 5ad6d11e5ac..b575e82bc60 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/descriptors/InlineClassRepresentation.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/descriptors/InlineClassRepresentation.kt @@ -18,5 +18,5 @@ class InlineClassRepresentation 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) } } \ No newline at end of file diff --git a/core/compiler.common/src/org/jetbrains/kotlin/descriptors/MultiFieldValueClassRepresentation.kt b/core/compiler.common/src/org/jetbrains/kotlin/descriptors/MultiFieldValueClassRepresentation.kt index 9f90302f070..a4947ba88d3 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/descriptors/MultiFieldValueClassRepresentation.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/descriptors/MultiFieldValueClassRepresentation.kt @@ -17,5 +17,5 @@ class MultiFieldValueClassRepresentation( } 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] } \ No newline at end of file diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt index afc1abb36b5..ca5df14f39b 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt @@ -32,7 +32,7 @@ interface TypeSystemCommonBackendContext : TypeSystemContext { fun TypeConstructorMarker.isInlineClass(): Boolean fun TypeConstructorMarker.isMultiFieldValueClass(): Boolean - fun TypeConstructorMarker.valueClassRepresentationTypeMarkersList(): List>? + fun TypeConstructorMarker.getValueClassProperties(): List>? fun TypeConstructorMarker.isInnerClass(): Boolean fun TypeParameterMarker.getRepresentativeUpperBound(): KotlinTypeMarker fun KotlinTypeMarker.getUnsubstitutedUnderlyingType(): KotlinTypeMarker? diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt index efb3f2a4018..483addb3266 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -749,7 +749,7 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy return (declarationDescriptor as? ClassDescriptor)?.valueClassRepresentation is MultiFieldValueClassRepresentation } - override fun TypeConstructorMarker.valueClassRepresentationTypeMarkersList(): List>? { + override fun TypeConstructorMarker.getValueClassProperties(): List>? { require(this is TypeConstructor, this::errorMessage) return (declarationDescriptor as? ClassDescriptor)?.valueClassRepresentation?.underlyingPropertyNamesToTypes } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt index 7fff69f8997..5c0d41a15bf 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt @@ -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 diff --git a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/IrParcelSerializerFactory.kt b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/IrParcelSerializerFactory.kt index bbef5704eb4..cd28d880668 100644 --- a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/IrParcelSerializerFactory.kt +++ b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/IrParcelSerializerFactory.kt @@ -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