From 26211a0277a3016fab2a4c205e248af732c39ed8 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Tue, 29 Aug 2023 13:28:19 +0300 Subject: [PATCH] [FIR2IR] Extract logic of IR declarations generation into separate component. Part 12 This commit just moves methods which create IR callable declarations from Fir2IrClassifierStorage to newly created Fir2IrClassifiersGenerator Code in generators contains some errors (mostly because it refers to the logic of caching created declaration), and those errors will be fixed in the following commits --- .../kotlin/fir/backend/ConversionUtils.kt | 5 +- .../fir/backend/Fir2IrClassifierStorage.kt | 537 +---------------- .../kotlin/fir/backend/Fir2IrComponents.kt | 1 + .../fir/backend/Fir2IrComponentsStorage.kt | 1 + .../kotlin/fir/backend/Fir2IrConverter.kt | 14 +- .../kotlin/fir/backend/Fir2IrTypeConverter.kt | 2 +- .../Fir2IrCallableDeclarationsGenerator.kt | 12 +- .../generators/Fir2IrClassifiersGenerator.kt | 570 ++++++++++++++++++ .../Fir2IrLazyDeclarationsGenerator.kt | 25 +- .../kotlin/fir/lazy/Fir2IrLazyProperty.kt | 12 +- 10 files changed, 627 insertions(+), 552 deletions(-) create mode 100644 compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrClassifiersGenerator.kt 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 b10bbd56376..6c038aad414 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 @@ -11,8 +11,6 @@ import com.intellij.psi.tree.IElementType import org.jetbrains.kotlin.* import org.jetbrains.kotlin.backend.common.actualizer.IrActualizedResult import org.jetbrains.kotlin.builtins.StandardNames.DATA_CLASS_COMPONENT_PREFIX -import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.ValueClassRepresentation import org.jetbrains.kotlin.diagnostics.startOffsetSkippingComments import org.jetbrains.kotlin.fir.* @@ -32,7 +30,6 @@ import org.jetbrains.kotlin.fir.extensions.extensionService import org.jetbrains.kotlin.fir.extensions.generatedDeclarationsSymbolProvider import org.jetbrains.kotlin.fir.references.FirReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference -import org.jetbrains.kotlin.fir.references.FirThisReference import org.jetbrains.kotlin.fir.references.impl.FirPropertyFromParameterResolvedNamedReference import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol import org.jetbrains.kotlin.fir.resolve.* @@ -153,7 +150,7 @@ fun FirClassifierSymbol<*>.toSymbol( val coneClassLikeType = fir.expandedTypeRef.coneType as ConeClassLikeType coneClassLikeType.lookupTag.toSymbol(session) ?.toSymbol(typeOrigin, handleAnnotations) - ?: classifierStorage.getIrClassSymbolForNotFoundClass(coneClassLikeType.lookupTag) + ?: classifiersGenerator.createIrClassSymbolForNotFoundClass(coneClassLikeType.lookupTag) } is FirClassSymbol -> { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt index 8927ba89065..adb902a56bd 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt @@ -6,38 +6,26 @@ package org.jetbrains.kotlin.fir.backend import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.fir.containingClassForLocalAttr import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression -import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass -import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag import org.jetbrains.kotlin.fir.resolve.providers.firProvider -import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.resolve.providers.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag -import org.jetbrains.kotlin.fir.symbols.Fir2IrClassSymbol -import org.jetbrains.kotlin.fir.symbols.Fir2IrEnumEntrySymbol -import org.jetbrains.kotlin.fir.symbols.Fir2IrTypeAliasSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.fir.types.toLookupTag import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.impl.* import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl -import org.jetbrains.kotlin.ir.util.IdSignature -import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.StandardClassIds -import org.jetbrains.kotlin.utils.addToStdlib.runIf -import org.jetbrains.kotlin.utils.addToStdlib.runUnless class Fir2IrClassifierStorage( private val components: Fir2IrComponents, @@ -45,10 +33,6 @@ class Fir2IrClassifierStorage( ) : Fir2IrComponents by components { private val classCache: MutableMap = commonMemberStorage.classCache - private val localClassesCreatedOnTheFly: MutableMap = mutableMapOf() - - private var processMembersOfClassesOnTheFlyImmediately = false - private val typeAliasCache: MutableMap = mutableMapOf() private val typeParameterCache: MutableMap = commonMemberStorage.typeParameterCache @@ -76,7 +60,7 @@ class Fir2IrClassifierStorage( val firClass = classId.toSymbol(session)?.fir as FirRegularClass? ?: continue val irClass = irBuiltinSymbol.owner classCache[firClass] = irClass - processClassHeader(firClass, irClass) + classifiersGenerator.processClassHeader(firClass, irClass) declarationStorage.preCacheBuiltinClassMembers(firClass, irClass) } for ((primitiveClassId, primitiveArrayId) in StandardClassIds.primitiveArrayTypeByElementType) { @@ -85,59 +69,32 @@ class Fir2IrClassifierStorage( val irType = typeConverter.classIdToTypeMap[primitiveClassId] val irClass = irBuiltIns.primitiveArrayForType[irType]!!.owner classCache[firClass] = irClass - processClassHeader(firClass, irClass) + classifiersGenerator.processClassHeader(firClass, irClass) declarationStorage.preCacheBuiltinClassMembers(firClass, irClass) } } // Note: declareTypeParameters should be called before! - private fun IrClass.setThisReceiver(typeParameters: List) { - symbolTable.enterScope(this) - val typeArguments = typeParameters.map { - IrSimpleTypeImpl(getIrTypeParameterSymbol(it.symbol, ConversionTypeOrigin.DEFAULT), false, emptyList(), emptyList()) - } - thisReceiver = declareThisReceiverParameter( - thisType = IrSimpleTypeImpl(symbol, false, typeArguments, emptyList()), - thisOrigin = IrDeclarationOrigin.INSTANCE_RECEIVER - ) - symbolTable.leaveScope(this) - } internal fun preCacheTypeParameters(owner: FirTypeParameterRefsOwner, irOwnerSymbol: IrSymbol) { for ((index, typeParameter) in owner.typeParameters.withIndex()) { val original = typeParameter.symbol.fir getCachedIrTypeParameter(original) - ?: createIrTypeParameterWithoutBounds(original, index, irOwnerSymbol) + ?: classifiersGenerator.createIrTypeParameterWithoutBounds(original, index, irOwnerSymbol) if (owner is FirProperty && owner.isVar) { val context = ConversionTypeOrigin.SETTER getCachedIrTypeParameter(original, context) - ?: createIrTypeParameterWithoutBounds(original, index, irOwnerSymbol, context) + ?: classifiersGenerator.createIrTypeParameterWithoutBounds(original, index, irOwnerSymbol, context) } } } - internal fun IrTypeParametersContainer.setTypeParameters( + internal fun setTypeParameters( + irOwner: IrTypeParametersContainer, owner: FirTypeParameterRefsOwner, typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT ) { - typeParameters = owner.typeParameters.mapIndexedNotNull { index, typeParameter -> - if (typeParameter !is FirTypeParameter) return@mapIndexedNotNull null - getIrTypeParameter(typeParameter, index, symbol, typeOrigin).apply { - parent = this@setTypeParameters - if (superTypes.isEmpty()) { - superTypes = typeParameter.bounds.map { it.toIrType(typeOrigin) } - } - } - } - } - - private fun IrClass.declareTypeParameters(klass: FirClass) { - preCacheTypeParameters(klass, symbol) - setTypeParameters(klass) - if (klass is FirRegularClass) { - val fieldsForContextReceiversOfCurrentClass = getFieldsWithContextReceiversForClass(this, klass) - declarations.addAll(fieldsForContextReceiversOfCurrentClass) - } + classifiersGenerator.setTypeParameters(irOwner, owner, typeOrigin) } fun getFieldsWithContextReceiversForClass(irClass: IrClass, klass: FirClass): List { @@ -163,16 +120,6 @@ class Fir2IrClassifierStorage( } } - private fun IrClass.declareSupertypes(klass: FirClass) { - superTypes = klass.superTypeRefs.map { superTypeRef -> superTypeRef.toIrType() } - } - - private fun IrClass.declareValueClassRepresentation(klass: FirRegularClass) { - if (this !is Fir2IrLazyClass) { - valueClassRepresentation = computeValueClassRepresentation(klass) - } - } - fun getCachedIrClass(klass: FirClass): IrClass? { return if (klass is FirAnonymousObject || klass is FirRegularClass && klass.visibility == Visibilities.Local) { localStorage[klass] @@ -189,337 +136,34 @@ class Fir2IrClassifierStorage( return codeFragmentCache[codeFragment] } - private fun FirRegularClass.enumClassModality(): Modality { - return when { - declarations.any { it is FirCallableDeclaration && it.modality == Modality.ABSTRACT } -> { - Modality.ABSTRACT - } - declarations.none { - it is FirEnumEntry && isEnumEntryWhichRequiresSubclass(it) - } -> { - Modality.FINAL - } - hasAbstractMembersInScope() -> { - Modality.ABSTRACT - } - else -> { - Modality.OPEN - } - } - } - - private fun FirRegularClass.hasAbstractMembersInScope(): Boolean { - val scope = unsubstitutedScope() - val names = scope.getCallableNames() - var hasAbstract = false - for (name in names) { - scope.processFunctionsByName(name) { - if (it.isAbstract) { - hasAbstract = true - } - } - if (hasAbstract) return true - scope.processPropertiesByName(name) { - if (it.isAbstract) { - hasAbstract = true - } - } - if (hasAbstract) return true - } - return false - } - - // This function is called when we refer local class earlier than we reach its declaration - // This can happen e.g. when implicit return type has a local class constructor - private fun createLocalIrClassOnTheFly(klass: FirClass): IrClass { - // finding the parent class that actually contains the [klass] in the tree - it is the root one that should be created on the fly - val classOrLocalParent = generateSequence(klass) { c -> - (c as? FirRegularClass)?.containingClassForLocalAttr?.let { lookupTag -> - (session.firProvider.symbolProvider.getSymbolByLookupTag(lookupTag)?.fir as? FirClass)?.takeIf { - it.declarations.contains(c) - } - } - }.last() - val result = converter.processLocalClassAndNestedClassesOnTheFly(classOrLocalParent, temporaryParent) - // Note: usually member creation and f/o binding is delayed till non-local classes are processed in Fir2IrConverter - // If non-local classes are already created (this means we are in body translation) we do everything immediately - // The last variant is possible for local variables like 'val a = object : Any() { ... }' - if (processMembersOfClassesOnTheFlyImmediately) { - converter.processClassMembers(classOrLocalParent, result) - converter.bindFakeOverridesInClass(result) - } else { - localClassesCreatedOnTheFly[classOrLocalParent] = result - } - return if (classOrLocalParent === klass) result - else (getCachedIrClass(klass) - ?: error("Assuming that all nested classes of ${classOrLocalParent.classId.asString()} should already be cached")) - } - - // Note: this function is called exactly once, right after Fir2IrConverter finished f/o binding for regular classes - fun processMembersOfClassesCreatedOnTheFly() { - // After the call of this function, members of local classes may be processed immediately - // Before the call it's not possible, because f/o binding for regular classes isn't done yet - processMembersOfClassesOnTheFlyImmediately = true - for ((klass, irClass) in localClassesCreatedOnTheFly) { - converter.processClassMembers(klass, irClass) - // See the problem from KT-57441 -// class Wrapper { -// private val dummy = object: Bar {} -// private val bar = object: Bar by dummy {} -// } -// interface Bar { -// val foo: String -// get() = "" -// } - // When we are building bar.foo fake override, we should call dummy.foo, - // so we should have object : Bar.foo fake override to be built and bound. - converter.bindFakeOverridesInClass(irClass) - } - localClassesCreatedOnTheFly.clear() - } - - fun processClassHeader(klass: FirClass, irClass: IrClass = getCachedIrClass(klass)!!): IrClass { - irClass.declareTypeParameters(klass) - irClass.setThisReceiver(klass.typeParameters) - irClass.declareSupertypes(klass) - if (klass is FirRegularClass) { - irClass.declareValueClassRepresentation(klass) - } - return irClass - } - - private fun declareIrTypeAlias(signature: IdSignature?, factory: (IrTypeAliasSymbol) -> IrTypeAlias): IrTypeAlias = - if (signature == null) - factory(IrTypeAliasSymbolImpl()) - else - symbolTable.declareTypeAlias(signature, { Fir2IrTypeAliasSymbol(signature) }, factory) - - fun registerTypeAlias( + fun createAndCacheIrTypeAlias( typeAlias: FirTypeAlias, parent: IrDeclarationParent ): IrTypeAlias { - val signature = signatureComposer.composeSignature(typeAlias) - return typeAlias.convertWithOffsets { startOffset, endOffset -> - declareIrTypeAlias(signature) { symbol -> - preCacheTypeParameters(typeAlias, symbol) - val irTypeAlias = irFactory.createTypeAlias( - startOffset = startOffset, - endOffset = endOffset, - origin = IrDeclarationOrigin.DEFINED, - name = typeAlias.name, - visibility = components.visibilityConverter.convertToDescriptorVisibility(typeAlias.visibility), - symbol = symbol, - isActual = typeAlias.isActual, - expandedType = typeAlias.expandedTypeRef.toIrType(), - ).apply { - this.parent = parent - setTypeParameters(typeAlias) - if (parent is IrFile) { - parent.declarations += this - } - } - typeAliasCache[typeAlias] = irTypeAlias - irTypeAlias - } - } + return classifiersGenerator.createIrTypeAlias(typeAlias, parent) } internal fun getCachedTypeAlias(firTypeAlias: FirTypeAlias): IrTypeAlias? = typeAliasCache[firTypeAlias] - private fun declareIrClass(signature: IdSignature?, factory: (IrClassSymbol) -> IrClass): IrClass = - if (signature == null) - factory(IrClassSymbolImpl()) - else - symbolTable.declareClass(signature, { Fir2IrClassSymbol(signature) }, factory) - - fun registerIrClass( + fun createAndCacheIrClass( regularClass: FirRegularClass, parent: IrDeclarationParent, predefinedOrigin: IrDeclarationOrigin? = null ): IrClass { - val visibility = regularClass.visibility - val modality = when (regularClass.classKind) { - ClassKind.ENUM_CLASS -> regularClass.enumClassModality() - ClassKind.ANNOTATION_CLASS -> Modality.OPEN - else -> regularClass.modality ?: Modality.FINAL - } - val signature = runUnless(regularClass.isLocal || !configuration.linkViaSignatures) { - signatureComposer.composeSignature(regularClass) - } - val irClass = regularClass.convertWithOffsets { startOffset, endOffset -> - declareIrClass(signature) { symbol -> - irFactory.createClass( - startOffset = startOffset, - endOffset = endOffset, - origin = regularClass.computeIrOrigin(predefinedOrigin), - name = regularClass.name, - visibility = components.visibilityConverter.convertToDescriptorVisibility(visibility), - symbol = symbol, - kind = regularClass.classKind, - modality = modality, - isExternal = regularClass.isExternal, - isCompanion = regularClass.isCompanion, - isInner = regularClass.isInner, - isData = regularClass.isData, - isValue = regularClass.isInline, - isExpect = regularClass.isExpect, - isFun = regularClass.isFun - ).apply { - metadata = FirMetadataSource.Class(regularClass) - } - } - } - irClass.parent = parent - if (regularClass.visibility == Visibilities.Local) { - localStorage[regularClass] = irClass - } else { - classCache[regularClass] = irClass - } - return irClass + return classifiersGenerator.createIrClass(regularClass, parent, predefinedOrigin) } - fun registerIrAnonymousObject( + fun createAndCacheAnonymousObject( anonymousObject: FirAnonymousObject, visibility: Visibility = Visibilities.Local, name: Name = SpecialNames.NO_NAME_PROVIDED, irParent: IrDeclarationParent? = null ): IrClass { - val origin = IrDeclarationOrigin.DEFINED - val modality = Modality.FINAL - val irAnonymousObject = anonymousObject.convertWithOffsets { startOffset, endOffset -> - irFactory.createClass( - startOffset = startOffset, - endOffset = endOffset, - origin = origin, - name = name, - visibility = components.visibilityConverter.convertToDescriptorVisibility(visibility), - symbol = IrClassSymbolImpl(), - kind = anonymousObject.classKind, - modality = modality, - ).apply { - metadata = FirMetadataSource.Class(anonymousObject) - } - } - if (irParent != null) { - irAnonymousObject.parent = irParent - } - localStorage[anonymousObject] = irAnonymousObject - return irAnonymousObject + return classifiersGenerator.createAnonymousObject(anonymousObject, visibility, name, irParent) } - fun registerCodeFragmentClass(codeFragment: FirCodeFragment, containingFile: IrFile): IrClass { - val conversionData = codeFragment.conversionData - val signature = signatureComposer.composeSignature(codeFragment) - - val irClass = codeFragment.convertWithOffsets { startOffset, endOffset -> - declareIrClass(signature) { symbol -> - irFactory.createClass( - startOffset, - endOffset, - IrDeclarationOrigin.DEFINED, - conversionData.classId.shortClassName, - DescriptorVisibilities.PUBLIC, - symbol, - ClassKind.CLASS, - Modality.FINAL, - isExternal = false, - isCompanion = false, - isInner = false, - isData = false, - isValue = false, - isExpect = false, - isFun = false - ).apply { - metadata = FirMetadataSource.CodeFragment(codeFragment) - parent = containingFile - typeParameters = emptyList() - thisReceiver = declareThisReceiverParameter( - thisType = IrSimpleTypeImpl(symbol, false, emptyList(), emptyList()), - thisOrigin = IrDeclarationOrigin.INSTANCE_RECEIVER - ) - superTypes = listOf(irBuiltIns.anyType) - } - } - } - codeFragmentCache[codeFragment] = irClass - return irClass - } - - private fun getIrAnonymousObjectForEnumEntry(anonymousObject: FirAnonymousObject, name: Name, irParent: IrClass?): IrClass { - localStorage[anonymousObject]?.let { return it } - val irAnonymousObject = registerIrAnonymousObject(anonymousObject, Visibilities.Private, name, irParent) - processClassHeader(anonymousObject, irAnonymousObject) - return irAnonymousObject - } - - private fun createIrTypeParameterWithoutBounds( - typeParameter: FirTypeParameter, - index: Int, - ownerSymbol: IrSymbol, - typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT, - ): IrTypeParameter { - require(index >= 0) - val origin = typeParameter.computeIrOrigin() - val irTypeParameter = with(typeParameter) { - convertWithOffsets { startOffset, endOffset -> - signatureComposer.composeTypeParameterSignature( - index, ownerSymbol.signature - )?.let { signature -> - if (ownerSymbol is IrClassifierSymbol) { - symbolTable.declareGlobalTypeParameter( - signature, - symbolFactory = { IrTypeParameterPublicSymbolImpl(signature) } - ) { symbol -> - irFactory.createTypeParameter( - startOffset = startOffset, - endOffset = endOffset, - origin = origin, - name = name, - symbol = symbol, - variance = variance, - index = if (index < 0) 0 else index, - isReified = isReified, - ) - } - } else { - symbolTable.declareScopedTypeParameter( - signature, - symbolFactory = { IrTypeParameterPublicSymbolImpl(signature) } - ) { symbol -> - irFactory.createTypeParameter( - startOffset = startOffset, - endOffset = endOffset, - origin = origin, - name = name, - symbol = symbol, - variance = variance, - index = if (index < 0) 0 else index, - isReified = isReified, - ) - } - - } - } ?: irFactory.createTypeParameter( - startOffset = startOffset, - endOffset = endOffset, - origin = origin, - name = name, - symbol = IrTypeParameterSymbolImpl(), - variance = variance, - index = if (index < 0) 0 else index, - isReified = isReified, - ) - } - } - - // Cache the type parameter BEFORE processing its bounds/supertypes, to properly handle recursive type bounds. - if (typeOrigin.forSetter) { - typeParameterCacheForSetter[typeParameter] = irTypeParameter - } else { - typeParameterCache[typeParameter] = irTypeParameter - } - annotationGenerator.generate(irTypeParameter, typeParameter) - return irTypeParameter + fun createAndCacheCodeFragmentClass(codeFragment: FirCodeFragment, containingFile: IrFile): IrClass { + return classifiersGenerator.createCodeFragmentClass(codeFragment, containingFile) } internal fun getCachedIrTypeParameter( @@ -539,11 +183,7 @@ class Fir2IrClassifierStorage( typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT ): IrTypeParameter { getCachedIrTypeParameter(typeParameter, typeOrigin)?.let { return it } - return typeParameter.run { - val irTypeParameter = createIrTypeParameterWithoutBounds(typeParameter, index, ownerSymbol, typeOrigin) - irTypeParameter.superTypes = bounds.map { it.toIrType() } - irTypeParameter - } + return classifiersGenerator.createIrTypeParameterWithBounds(typeParameter, index, ownerSymbol, typeOrigin) } fun putEnumEntryClassInScope(enumEntry: FirEnumEntry, correspondingClass: IrClass) { @@ -552,12 +192,6 @@ class Fir2IrClassifierStorage( internal fun getCachedIrEnumEntry(enumEntry: FirEnumEntry): IrEnumEntry? = enumEntryCache[enumEntry] - private fun declareIrEnumEntry(signature: IdSignature?, factory: (IrEnumEntrySymbol) -> IrEnumEntry): IrEnumEntry = - if (signature == null) - factory(IrEnumEntrySymbolImpl()) - else - symbolTable.declareEnumEntry(signature, { Fir2IrEnumEntrySymbol(signature) }, factory) - fun getIrEnumEntry( enumEntry: FirEnumEntry, irParent: IrClass, @@ -574,7 +208,7 @@ class Fir2IrClassifierStorage( } else { irParent.origin } - return createIrEnumEntry( + return classifiersGenerator.createIrEnumEntry( enumEntry, irParent = irParent, predefinedOrigin = predefinedOrigin @@ -595,110 +229,8 @@ class Fir2IrClassifierStorage( } } - fun createIrEnumEntry( - enumEntry: FirEnumEntry, - irParent: IrClass?, - predefinedOrigin: IrDeclarationOrigin? = null, - ): IrEnumEntry { - return enumEntry.convertWithOffsets { startOffset, endOffset -> - val signature = signatureComposer.composeSignature(enumEntry) - val result = declareIrEnumEntry(signature) { symbol -> - val origin = enumEntry.computeIrOrigin(predefinedOrigin) - irFactory.createEnumEntry( - startOffset = startOffset, - endOffset = endOffset, - origin = origin, - name = enumEntry.name, - symbol = symbol, - ).apply { - declarationStorage.enterScope(this.symbol) - if (irParent != null) { - this.parent = irParent - } - if (isEnumEntryWhichRequiresSubclass(enumEntry)) { - // An enum entry with its own members requires an anonymous object generated. - // Otherwise, this is a default-ish enum entry whose initializer would be a delegating constructor call, - // which will be translated via visitor later. - val klass = getIrAnonymousObjectForEnumEntry( - (enumEntry.initializer as FirAnonymousObjectExpression).anonymousObject, enumEntry.name, irParent - ) - this.correspondingClass = klass - } - declarationStorage.leaveScope(this.symbol) - } - } - enumEntryCache[enumEntry] = result - result - } - } - - private fun isEnumEntryWhichRequiresSubclass(enumEntry: FirEnumEntry): Boolean { - val initializer = enumEntry.initializer - return initializer is FirAnonymousObjectExpression && initializer.anonymousObject.declarations.any { it !is FirConstructor } - } - fun getIrClassSymbol(firClassSymbol: FirClassSymbol<*>): IrClassSymbol { - val firClass = firClassSymbol.fir - getCachedIrClass(firClass)?.let { return it.symbol } - if (firClass is FirAnonymousObject || firClass is FirRegularClass && firClass.visibility == Visibilities.Local) { - return createLocalIrClassOnTheFly(firClass).symbol - } - firClass as FirRegularClass - val classId = firClassSymbol.classId - val parentId = classId.outerClassId - val parentClass = parentId?.let { session.symbolProvider.getClassLikeSymbolByClassId(it) } - val irParent = declarationStorage.findIrParent(classId.packageFqName, parentClass?.toLookupTag(), firClassSymbol, firClass.origin)!! - - // firClass may be referenced by some parent's type parameters as a bound. In that case, getIrClassSymbol will be called recursively. - getCachedIrClass(firClass)?.let { return it.symbol } - - val signature = runIf(configuration.linkViaSignatures) { - signatureComposer.composeSignature(firClass) - } - val irClass = firClass.convertWithOffsets { startOffset, endOffset -> - declareIrClass(signature) { irClassSymbol -> - val firClassOrigin = firClass.irOrigin(session.firProvider) - Fir2IrLazyClass(components, startOffset, endOffset, firClassOrigin, firClass, irClassSymbol).apply { - parent = irParent - } - } - } - classCache[firClass] = irClass - // NB: this is needed to prevent recursions in case of self bounds - (irClass as Fir2IrLazyClass).prepareTypeParameters() - - return irClass.symbol - } - - @OptIn(IrSymbolInternals::class) - fun getIrClassSymbolForNotFoundClass(classLikeLookupTag: ConeClassLikeLookupTag): IrClassSymbol { - val classId = classLikeLookupTag.classId - val signature = IdSignature.CommonSignature( - packageFqName = classId.packageFqName.asString(), - declarationFqName = classId.relativeClassName.asString(), - id = 0, - mask = 0, - description = null, - ) - - val parentId = classId.outerClassId - val parentClass = parentId?.let { getIrClassSymbolForNotFoundClass(it.toLookupTag()) } - val irParent = parentClass?.owner ?: declarationStorage.getIrExternalPackageFragment(classId.packageFqName) - - return symbolTable.referenceClass(signature, { Fir2IrClassSymbol(signature) }) { - irFactory.createClass( - startOffset = UNDEFINED_OFFSET, - endOffset = UNDEFINED_OFFSET, - origin = IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB, - name = classId.shortClassName, - visibility = DescriptorVisibilities.DEFAULT_VISIBILITY, - symbol = it, - kind = ClassKind.CLASS, - modality = Modality.FINAL, - ).apply { - parent = irParent - } - } + return classifiersGenerator.createIrClassSymbolByFirSymbol(firClassSymbol) } fun getIrTypeParameterSymbol( @@ -715,40 +247,9 @@ class Fir2IrClassifierStorage( } if (components.configuration.allowNonCachedDeclarations) { - val firTypeParameterOwnerSymbol = firTypeParameter.containingDeclarationSymbol - val firTypeParameterOwner = firTypeParameterOwnerSymbol.fir as FirTypeParameterRefsOwner - val index = firTypeParameterOwner.typeParameters.indexOf(firTypeParameter).also { check(it >= 0) } - - val isSetter = firTypeParameterOwner is FirPropertyAccessor && firTypeParameterOwner.isSetter - val conversionTypeOrigin = if (isSetter) ConversionTypeOrigin.SETTER else ConversionTypeOrigin.DEFAULT - - return createIrTypeParameterWithoutBounds(firTypeParameter, index, IrTypeParameterSymbolImpl(), conversionTypeOrigin).apply { - superTypes = firTypeParameter.bounds.map { it.toIrType(typeConverter) } - }.symbol + return classifiersGenerator.createIrTypeParameterForNonCachedDeclaration(firTypeParameter) } error("Cannot find cached type parameter by FIR symbol: ${firTypeParameterSymbol.name} of the owner: ${firTypeParameter.containingDeclarationSymbol}") } - - private val temporaryParent by lazy { - irFactory.createSimpleFunction( - startOffset = UNDEFINED_OFFSET, - endOffset = UNDEFINED_OFFSET, - origin = IrDeclarationOrigin.DEFINED, - name = Name.special(""), - visibility = DescriptorVisibilities.PRIVATE, - isInline = false, - isExpect = false, - returnType = irBuiltIns.unitType, - modality = Modality.FINAL, - symbol = IrSimpleFunctionSymbolImpl(), - isTailrec = false, - isSuspend = false, - isOperator = false, - isInfix = false, - isExternal = false, - ).apply { - parent = IrExternalPackageFragmentImpl(IrExternalPackageFragmentSymbolImpl(), FqName.ROOT) - } - } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponents.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponents.kt index 18ca4e31152..70745575504 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponents.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponents.kt @@ -35,6 +35,7 @@ interface Fir2IrComponents { val visibilityConverter: Fir2IrVisibilityConverter val callablesGenerator: Fir2IrCallableDeclarationsGenerator + val classifiersGenerator: Fir2IrClassifiersGenerator val lazyDeclarationsGenerator: Fir2IrLazyDeclarationsGenerator val annotationGenerator: AnnotationGenerator diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt index dc2c5601a7e..20343fb02a8 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt @@ -38,6 +38,7 @@ class Fir2IrComponentsStorage( override val declarationStorage: Fir2IrDeclarationStorage = Fir2IrDeclarationStorage(this, moduleDescriptor, commonMemberStorage) override val callablesGenerator: Fir2IrCallableDeclarationsGenerator = Fir2IrCallableDeclarationsGenerator(this) + override val classifiersGenerator: Fir2IrClassifiersGenerator = Fir2IrClassifiersGenerator(this) override val lazyDeclarationsGenerator: Fir2IrLazyDeclarationsGenerator = Fir2IrLazyDeclarationsGenerator(this) // builtins should go after storages and generators, because they use them during initialization diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt index cde88c26ea6..6b30989be84 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt @@ -92,7 +92,7 @@ class Fir2IrConverter( postponedDeclarationsForFakeOverridesBinding.clear() // Do (3) and (4) for local classes encountered during (3) - classifierStorage.processMembersOfClassesCreatedOnTheFly() + classifiersGenerator.processMembersOfClassesCreatedOnTheFly() // 5. Body processing // If we encounter local class / anonymous object here, then we perform all (1)-(5) stages immediately @@ -156,7 +156,7 @@ class Fir2IrConverter( for (declaration in file.declarations) { when (declaration) { is FirRegularClass -> registerClassAndNestedClasses(declaration, irFile) - is FirCodeFragment -> classifierStorage.registerCodeFragmentClass(declaration, irFile) + is FirCodeFragment -> classifierStorage.createAndCacheCodeFragmentClass(declaration, irFile) else -> {} } } @@ -167,7 +167,7 @@ class Fir2IrConverter( file.declarations.forEach { when (it) { is FirRegularClass -> processClassAndNestedClassHeaders(it) - is FirTypeAlias -> classifierStorage.registerTypeAlias(it, declarationStorage.getIrFile(file)) + is FirTypeAlias -> classifierStorage.createAndCacheIrTypeAlias(it, declarationStorage.getIrFile(file)) else -> {} } } @@ -373,8 +373,8 @@ class Fir2IrConverter( classifierStorage.getCachedIrClass(klass)?.apply { this.parent = parent } ?: when (klass) { - is FirRegularClass -> classifierStorage.registerIrClass(klass, parent) - is FirAnonymousObject -> classifierStorage.registerIrAnonymousObject(klass, irParent = parent) + is FirRegularClass -> classifierStorage.createAndCacheIrClass(klass, parent) + is FirAnonymousObject -> classifierStorage.createAndCacheAnonymousObject(klass, irParent = parent) } registerNestedClasses(klass, irClass) return irClass @@ -396,7 +396,7 @@ class Fir2IrConverter( } private fun processClassAndNestedClassHeaders(klass: FirClass) { - classifierStorage.processClassHeader(klass) + classifiersGenerator.processClassHeader(klass) processNestedClassHeaders(klass) } @@ -437,7 +437,7 @@ class Fir2IrConverter( registerClassAndNestedClasses(scriptStatement, irScript) processClassAndNestedClassHeaders(scriptStatement) } - is FirTypeAlias -> classifierStorage.registerTypeAlias(scriptStatement, irScript) + is FirTypeAlias -> classifierStorage.createAndCacheIrTypeAlias(scriptStatement, irScript) else -> {} } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt index 144b437ccaf..04ea6eab89b 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt @@ -124,7 +124,7 @@ class Fir2IrTypeConverter( ?: lookupTag.toSymbol(session)?.toSymbol(typeOrigin) { typeAnnotations += with(annotationGenerator) { it.toIrAnnotations() } } - ?: (lookupTag as? ConeClassLikeLookupTag)?.let(classifierStorage::getIrClassSymbolForNotFoundClass) + ?: (lookupTag as? ConeClassLikeLookupTag)?.let(classifiersGenerator::createIrClassSymbolForNotFoundClass) ?: return createErrorType() when { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrCallableDeclarationsGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrCallableDeclarationsGenerator.kt index 6826f8c1970..73cc1c72423 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrCallableDeclarationsGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrCallableDeclarationsGenerator.kt @@ -452,11 +452,9 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi if (propertyAccessorForAnnotations != null) { convertAnnotationsForNonDeclaredMembers(propertyAccessorForAnnotations, origin) } - with(classifierStorage) { - setTypeParameters( - property, if (isSetter) ConversionTypeOrigin.SETTER else ConversionTypeOrigin.DEFAULT - ) - } + classifiersGenerator.setTypeParameters( + this, property, if (isSetter) ConversionTypeOrigin.SETTER else ConversionTypeOrigin.DEFAULT + ) val dispatchReceiverType = computeDispatchReceiverType(this, property, irParent) // NB: we should enter accessor' scope before declaring its parameters // (both setter default and receiver ones, if any) @@ -686,9 +684,7 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi val containingClass = computeContainingClass(irParent) val parent = this if (function is FirSimpleFunction || function is FirConstructor) { - with(classifierStorage) { - setTypeParameters(function) - } + classifiersGenerator.setTypeParameters(this, function) } val typeOrigin = if (forSetter) ConversionTypeOrigin.SETTER else ConversionTypeOrigin.DEFAULT if (function is FirDefaultPropertySetter) { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrClassifiersGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrClassifiersGenerator.kt new file mode 100644 index 00000000000..419338f442d --- /dev/null +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrClassifiersGenerator.kt @@ -0,0 +1,570 @@ +/* + * Copyright 2010-2023 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.backend.generators + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.fir.backend.* +import org.jetbrains.kotlin.fir.containingClassForLocalAttr +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.utils.* +import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression +import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass +import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag +import org.jetbrains.kotlin.fir.resolve.providers.firProvider +import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider +import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag +import org.jetbrains.kotlin.fir.symbols.Fir2IrClassSymbol +import org.jetbrains.kotlin.fir.symbols.Fir2IrEnumEntrySymbol +import org.jetbrains.kotlin.fir.symbols.Fir2IrTypeAliasSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.types.toLookupTag +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl +import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.symbols.impl.* +import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl +import org.jetbrains.kotlin.ir.util.IdSignature +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.name.SpecialNames +import org.jetbrains.kotlin.utils.addToStdlib.runUnless + +class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrComponents by components { + private val localClassesCreatedOnTheFly: MutableMap = mutableMapOf() + + private var processMembersOfClassesOnTheFlyImmediately = false + + internal fun setTypeParameters( + irOwner: IrTypeParametersContainer, + owner: FirTypeParameterRefsOwner, + typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT + ) { + irOwner.typeParameters = owner.typeParameters.mapIndexedNotNull { index, typeParameter -> + if (typeParameter !is FirTypeParameter) return@mapIndexedNotNull null + classifierStorage.getIrTypeParameter(typeParameter, index, irOwner.symbol, typeOrigin).apply { + parent = irOwner + if (superTypes.isEmpty()) { + superTypes = typeParameter.bounds.map { it.toIrType(typeOrigin) } + } + } + } + } + + private fun IrClass.declareTypeParameters(klass: FirClass) { + classifierStorage.preCacheTypeParameters(klass, symbol) + setTypeParameters(this, klass) + if (klass is FirRegularClass) { + val fieldsForContextReceiversOfCurrentClass = classifierStorage.getFieldsWithContextReceiversForClass(this, klass) + declarations.addAll(fieldsForContextReceiversOfCurrentClass) + } + } + + private fun IrClass.declareSupertypes(klass: FirClass) { + superTypes = klass.superTypeRefs.map { superTypeRef -> superTypeRef.toIrType() } + } + + private fun IrClass.declareValueClassRepresentation(klass: FirRegularClass) { + if (this !is Fir2IrLazyClass) { + valueClassRepresentation = computeValueClassRepresentation(klass) + } + } + + private fun FirRegularClass.enumClassModality(): Modality { + return when { + declarations.any { it is FirCallableDeclaration && it.modality == Modality.ABSTRACT } -> { + Modality.ABSTRACT + } + declarations.none { + it is FirEnumEntry && isEnumEntryWhichRequiresSubclass(it) + } -> { + Modality.FINAL + } + hasAbstractMembersInScope() -> { + Modality.ABSTRACT + } + else -> { + Modality.OPEN + } + } + } + + private fun FirRegularClass.hasAbstractMembersInScope(): Boolean { + val scope = unsubstitutedScope() + val names = scope.getCallableNames() + var hasAbstract = false + for (name in names) { + scope.processFunctionsByName(name) { + if (it.isAbstract) { + hasAbstract = true + } + } + if (hasAbstract) return true + scope.processPropertiesByName(name) { + if (it.isAbstract) { + hasAbstract = true + } + } + if (hasAbstract) return true + } + return false + } + + // TODO: it's worth to move this onTheFly stuff back to classifier storage + // This function is called when we refer local class earlier than we reach its declaration + // This can happen e.g. when implicit return type has a local class constructor + private fun createLocalIrClassOnTheFly(klass: FirClass): IrClass { + // finding the parent class that actually contains the [klass] in the tree - it is the root one that should be created on the fly + val classOrLocalParent = generateSequence(klass) { c -> + (c as? FirRegularClass)?.containingClassForLocalAttr?.let { lookupTag -> + (session.firProvider.symbolProvider.getSymbolByLookupTag(lookupTag)?.fir as? FirClass)?.takeIf { + it.declarations.contains(c) + } + } + }.last() + val result = converter.processLocalClassAndNestedClassesOnTheFly(classOrLocalParent, temporaryParent) + // Note: usually member creation and f/o binding is delayed till non-local classes are processed in Fir2IrConverter + // If non-local classes are already created (this means we are in body translation) we do everything immediately + // The last variant is possible for local variables like 'val a = object : Any() { ... }' + if (processMembersOfClassesOnTheFlyImmediately) { + converter.processClassMembers(classOrLocalParent, result) + converter.bindFakeOverridesInClass(result) + } else { + localClassesCreatedOnTheFly[classOrLocalParent] = result + } + return if (classOrLocalParent === klass) result + else (classifierStorage.getCachedIrClass(klass) + ?: error("Assuming that all nested classes of ${classOrLocalParent.classId.asString()} should already be cached")) + } + + // Note: this function is called exactly once, right after Fir2IrConverter finished f/o binding for regular classes + fun processMembersOfClassesCreatedOnTheFly() { + // After the call of this function, members of local classes may be processed immediately + // Before the call it's not possible, because f/o binding for regular classes isn't done yet + processMembersOfClassesOnTheFlyImmediately = true + for ((klass, irClass) in localClassesCreatedOnTheFly) { + converter.processClassMembers(klass, irClass) + // See the problem from KT-57441 +// class Wrapper { +// private val dummy = object: Bar {} +// private val bar = object: Bar by dummy {} +// } +// interface Bar { +// val foo: String +// get() = "" +// } + // When we are building bar.foo fake override, we should call dummy.foo, + // so we should have object : Bar.foo fake override to be built and bound. + converter.bindFakeOverridesInClass(irClass) + } + localClassesCreatedOnTheFly.clear() + } + + fun processClassHeader(klass: FirClass, irClass: IrClass = classifierStorage.getCachedIrClass(klass)!!): IrClass { + irClass.declareTypeParameters(klass) + irClass.setThisReceiver(klass.typeParameters) + irClass.declareSupertypes(klass) + if (klass is FirRegularClass) { + irClass.declareValueClassRepresentation(klass) + } + return irClass + } + + private fun IrClass.setThisReceiver(typeParameters: List) { + symbolTable.enterScope(this) + val typeArguments = typeParameters.map { + IrSimpleTypeImpl(classifierStorage.getIrTypeParameterSymbol(it.symbol, ConversionTypeOrigin.DEFAULT), false, emptyList(), emptyList()) + } + thisReceiver = declareThisReceiverParameter( + thisType = IrSimpleTypeImpl(symbol, false, typeArguments, emptyList()), + thisOrigin = IrDeclarationOrigin.INSTANCE_RECEIVER + ) + symbolTable.leaveScope(this) + } + + + private fun declareIrTypeAlias(signature: IdSignature?, factory: (IrTypeAliasSymbol) -> IrTypeAlias): IrTypeAlias = + if (signature == null) + factory(IrTypeAliasSymbolImpl()) + else + symbolTable.declareTypeAlias(signature, { Fir2IrTypeAliasSymbol(signature) }, factory) + + fun createIrTypeAlias( + typeAlias: FirTypeAlias, + parent: IrDeclarationParent + ): IrTypeAlias = typeAlias.convertWithOffsets { startOffset, endOffset -> + val signature = signatureComposer.composeSignature(typeAlias) + declareIrTypeAlias(signature) { symbol -> + classifierStorage.preCacheTypeParameters(typeAlias, symbol) + val irTypeAlias = irFactory.createTypeAlias( + startOffset = startOffset, + endOffset = endOffset, + origin = IrDeclarationOrigin.DEFINED, + name = typeAlias.name, + visibility = components.visibilityConverter.convertToDescriptorVisibility(typeAlias.visibility), + symbol = symbol, + isActual = typeAlias.isActual, + expandedType = typeAlias.expandedTypeRef.toIrType(), + ).apply { + this.parent = parent + setTypeParameters(this, typeAlias) + if (parent is IrFile) { + parent.declarations += this + } + } + typeAliasCache[typeAlias] = irTypeAlias + irTypeAlias + } + } + + fun declareIrClass(signature: IdSignature?, factory: (IrClassSymbol) -> IrClass): IrClass { + return if (signature == null) + factory(IrClassSymbolImpl()) + else + symbolTable.declareClass(signature, { Fir2IrClassSymbol(signature) }, factory) + } + + fun createIrClass( + regularClass: FirRegularClass, + parent: IrDeclarationParent, + predefinedOrigin: IrDeclarationOrigin? = null + ): IrClass { + val visibility = regularClass.visibility + val modality = when (regularClass.classKind) { + ClassKind.ENUM_CLASS -> regularClass.enumClassModality() + ClassKind.ANNOTATION_CLASS -> Modality.OPEN + else -> regularClass.modality ?: Modality.FINAL + } + val signature = runUnless(regularClass.isLocal || !configuration.linkViaSignatures) { + signatureComposer.composeSignature(regularClass) + } + val irClass = regularClass.convertWithOffsets { startOffset, endOffset -> + declareIrClass(signature) { symbol -> + irFactory.createClass( + startOffset = startOffset, + endOffset = endOffset, + origin = regularClass.computeIrOrigin(predefinedOrigin), + name = regularClass.name, + visibility = components.visibilityConverter.convertToDescriptorVisibility(visibility), + symbol = symbol, + kind = regularClass.classKind, + modality = modality, + isExternal = regularClass.isExternal, + isCompanion = regularClass.isCompanion, + isInner = regularClass.isInner, + isData = regularClass.isData, + isValue = regularClass.isInline, + isExpect = regularClass.isExpect, + isFun = regularClass.isFun + ).apply { + metadata = FirMetadataSource.Class(regularClass) + } + } + } + irClass.parent = parent + if (regularClass.visibility == Visibilities.Local) { + localStorage[regularClass] = irClass + } else { + classCache[regularClass] = irClass + } + return irClass + } + + fun createAnonymousObject( + anonymousObject: FirAnonymousObject, + visibility: Visibility = Visibilities.Local, + name: Name = SpecialNames.NO_NAME_PROVIDED, + irParent: IrDeclarationParent? = null + ): IrClass { + val origin = IrDeclarationOrigin.DEFINED + val modality = Modality.FINAL + val irAnonymousObject = anonymousObject.convertWithOffsets { startOffset, endOffset -> + irFactory.createClass( + startOffset = startOffset, + endOffset = endOffset, + origin = origin, + name = name, + visibility = components.visibilityConverter.convertToDescriptorVisibility(visibility), + symbol = IrClassSymbolImpl(), + kind = anonymousObject.classKind, + modality = modality, + ).apply { + metadata = FirMetadataSource.Class(anonymousObject) + } + } + if (irParent != null) { + irAnonymousObject.parent = irParent + } + localStorage[anonymousObject] = irAnonymousObject + return irAnonymousObject + } + + fun createCodeFragmentClass(codeFragment: FirCodeFragment, containingFile: IrFile): IrClass { + val conversionData = codeFragment.conversionData + val signature = signatureComposer.composeSignature(codeFragment) + + val irClass = codeFragment.convertWithOffsets { startOffset, endOffset -> + declareIrClass(signature) { symbol -> + irFactory.createClass( + startOffset, + endOffset, + IrDeclarationOrigin.DEFINED, + conversionData.classId.shortClassName, + DescriptorVisibilities.PUBLIC, + symbol, + ClassKind.CLASS, + Modality.FINAL, + isExternal = false, + isCompanion = false, + isInner = false, + isData = false, + isValue = false, + isExpect = false, + isFun = false + ).apply { + metadata = FirMetadataSource.CodeFragment(codeFragment) + parent = containingFile + typeParameters = emptyList() + thisReceiver = declareThisReceiverParameter( + thisType = IrSimpleTypeImpl(symbol, false, emptyList(), emptyList()), + thisOrigin = IrDeclarationOrigin.INSTANCE_RECEIVER + ) + superTypes = listOf(irBuiltIns.anyType) + } + } + } + codeFragmentCache[codeFragment] = irClass + return irClass + } + + private fun getIrAnonymousObjectForEnumEntry(anonymousObject: FirAnonymousObject, name: Name, irParent: IrClass?): IrClass { + localStorage[anonymousObject]?.let { return it } + val irAnonymousObject = classifierStorage.createAndCacheAnonymousObject(anonymousObject, Visibilities.Private, name, irParent) + processClassHeader(anonymousObject, irAnonymousObject) + return irAnonymousObject + } + + fun createIrTypeParameterWithBounds( + typeParameter: FirTypeParameter, + index: Int, + ownerSymbol: IrSymbol, + typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT, + ): IrTypeParameter { + val irTypeParameter = createIrTypeParameterWithoutBounds(typeParameter, index, ownerSymbol, typeOrigin) + irTypeParameter.superTypes = typeParameter.bounds.map { it.toIrType() } + return irTypeParameter + } + + fun createIrTypeParameterWithoutBounds( + typeParameter: FirTypeParameter, + index: Int, + ownerSymbol: IrSymbol, + typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT, + ): IrTypeParameter { + require(index >= 0) + val origin = typeParameter.computeIrOrigin() + val irTypeParameter = with(typeParameter) { + convertWithOffsets { startOffset, endOffset -> + signatureComposer.composeTypeParameterSignature( + index, ownerSymbol.signature + )?.let { signature -> + if (ownerSymbol is IrClassifierSymbol) { + symbolTable.declareGlobalTypeParameter( + signature, + symbolFactory = { IrTypeParameterPublicSymbolImpl(signature) } + ) { symbol -> + irFactory.createTypeParameter( + startOffset = startOffset, + endOffset = endOffset, + origin = origin, + name = name, + symbol = symbol, + variance = variance, + index = if (index < 0) 0 else index, + isReified = isReified, + ) + } + } else { + symbolTable.declareScopedTypeParameter( + signature, + symbolFactory = { IrTypeParameterPublicSymbolImpl(signature) } + ) { symbol -> + irFactory.createTypeParameter( + startOffset = startOffset, + endOffset = endOffset, + origin = origin, + name = name, + symbol = symbol, + variance = variance, + index = if (index < 0) 0 else index, + isReified = isReified, + ) + } + + } + } ?: irFactory.createTypeParameter( + startOffset = startOffset, + endOffset = endOffset, + origin = origin, + name = name, + symbol = IrTypeParameterSymbolImpl(), + variance = variance, + index = if (index < 0) 0 else index, + isReified = isReified, + ) + } + } + + // Cache the type parameter BEFORE processing its bounds/supertypes, to properly handle recursive type bounds. + if (typeOrigin.forSetter) { + typeParameterCacheForSetter[typeParameter] = irTypeParameter + } else { + typeParameterCache[typeParameter] = irTypeParameter + } + annotationGenerator.generate(irTypeParameter, typeParameter) + return irTypeParameter + } + + private fun declareIrEnumEntry(signature: IdSignature?, factory: (IrEnumEntrySymbol) -> IrEnumEntry): IrEnumEntry { + return if (signature == null) + factory(IrEnumEntrySymbolImpl()) + else + symbolTable.declareEnumEntry(signature, { Fir2IrEnumEntrySymbol(signature) }, factory) + } + + fun createIrEnumEntry( + enumEntry: FirEnumEntry, + irParent: IrClass?, + predefinedOrigin: IrDeclarationOrigin? = null, + ): IrEnumEntry { + return enumEntry.convertWithOffsets { startOffset, endOffset -> + val signature = signatureComposer.composeSignature(enumEntry) + val result = declareIrEnumEntry(signature) { symbol -> + val origin = enumEntry.computeIrOrigin(predefinedOrigin) + irFactory.createEnumEntry( + startOffset = startOffset, + endOffset = endOffset, + origin = origin, + name = enumEntry.name, + symbol = symbol, + ).apply { + declarationStorage.enterScope(this.symbol) + if (irParent != null) { + this.parent = irParent + } + if (isEnumEntryWhichRequiresSubclass(enumEntry)) { + // An enum entry with its own members requires an anonymous object generated. + // Otherwise, this is a default-ish enum entry whose initializer would be a delegating constructor call, + // which will be translated via visitor later. + val klass = getIrAnonymousObjectForEnumEntry( + (enumEntry.initializer as FirAnonymousObjectExpression).anonymousObject, enumEntry.name, irParent + ) + this.correspondingClass = klass + } + declarationStorage.leaveScope(this.symbol) + } + } + enumEntryCache[enumEntry] = result + result + } + } + + private fun isEnumEntryWhichRequiresSubclass(enumEntry: FirEnumEntry): Boolean { + val initializer = enumEntry.initializer + return initializer is FirAnonymousObjectExpression && initializer.anonymousObject.declarations.any { it !is FirConstructor } + } + + @OptIn(IrSymbolInternals::class) + fun createIrClassSymbolForNotFoundClass(classLikeLookupTag: ConeClassLikeLookupTag): IrClassSymbol { + val classId = classLikeLookupTag.classId + val signature = IdSignature.CommonSignature( + packageFqName = classId.packageFqName.asString(), + declarationFqName = classId.relativeClassName.asString(), + id = 0, + mask = 0, + description = null, + ) + + val parentId = classId.outerClassId + val parentClass = parentId?.let { createIrClassSymbolForNotFoundClass(it.toLookupTag()) } + val irParent = parentClass?.owner ?: declarationStorage.getIrExternalPackageFragment(classId.packageFqName) + + return symbolTable.referenceClass(signature, { Fir2IrClassSymbol(signature) }) { + irFactory.createClass( + startOffset = UNDEFINED_OFFSET, + endOffset = UNDEFINED_OFFSET, + origin = IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB, + name = classId.shortClassName, + visibility = DescriptorVisibilities.DEFAULT_VISIBILITY, + symbol = it, + kind = ClassKind.CLASS, + modality = Modality.FINAL, + ).apply { + parent = irParent + } + } + } + + // TODO: should be decomposed + fun createIrClassSymbolByFirSymbol(firClassSymbol: FirClassSymbol<*>): IrClassSymbol { + val firClass = firClassSymbol.fir + classifierStorage.getCachedIrClass(firClass)?.let { return it.symbol } + if (firClass is FirAnonymousObject || firClass is FirRegularClass && firClass.visibility == Visibilities.Local) { + return createLocalIrClassOnTheFly(firClass).symbol + } + firClass as FirRegularClass + val classId = firClassSymbol.classId + val parentId = classId.outerClassId + val parentClass = parentId?.let { session.symbolProvider.getClassLikeSymbolByClassId(it) } + val irParent = declarationStorage.findIrParent(classId.packageFqName, parentClass?.toLookupTag(), firClassSymbol, firClass.origin)!! + + // firClass may be referenced by some parent's type parameters as a bound. In that case, getIrClassSymbol will be called recursively. + classifierStorage.getCachedIrClass(firClass)?.let { return it.symbol } + + val irClass = lazyDeclarationsGenerator.createIrLazyClass(firClass, irParent) + classCache[firClass] = irClass + // NB: this is needed to prevent recursions in case of self bounds + (irClass as Fir2IrLazyClass).prepareTypeParameters() + + return irClass.symbol + } + + + fun createIrTypeParameterForNonCachedDeclaration(firTypeParameter: FirTypeParameter): IrTypeParameterSymbol { + val firTypeParameterOwnerSymbol = firTypeParameter.containingDeclarationSymbol + val firTypeParameterOwner = firTypeParameterOwnerSymbol.fir as FirTypeParameterRefsOwner + val index = firTypeParameterOwner.typeParameters.indexOf(firTypeParameter).also { check(it >= 0) } + + val isSetter = firTypeParameterOwner is FirPropertyAccessor && firTypeParameterOwner.isSetter + val conversionTypeOrigin = if (isSetter) ConversionTypeOrigin.SETTER else ConversionTypeOrigin.DEFAULT + + return createIrTypeParameterWithoutBounds(firTypeParameter, index, IrTypeParameterSymbolImpl(), conversionTypeOrigin).apply { + superTypes = firTypeParameter.bounds.map { it.toIrType(typeConverter) } + }.symbol + } + + private val temporaryParent by lazy { + irFactory.createSimpleFunction( + startOffset = UNDEFINED_OFFSET, + endOffset = UNDEFINED_OFFSET, + origin = IrDeclarationOrigin.DEFINED, + name = Name.special(""), + visibility = DescriptorVisibilities.PRIVATE, + isInline = false, + isExpect = false, + returnType = irBuiltIns.unitType, + modality = Modality.FINAL, + symbol = IrSimpleFunctionSymbolImpl(), + isTailrec = false, + isSuspend = false, + isOperator = false, + isInfix = false, + isExternal = false, + ).apply { + parent = IrExternalPackageFragmentImpl(IrExternalPackageFragmentSymbolImpl(), FqName.ROOT) + } + } +} diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyDeclarationsGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyDeclarationsGenerator.kt index 659bd0c0c66..36d9dc23ea6 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyDeclarationsGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyDeclarationsGenerator.kt @@ -7,8 +7,11 @@ package org.jetbrains.kotlin.fir.backend.generators import org.jetbrains.kotlin.fir.backend.Fir2IrComponents import org.jetbrains.kotlin.fir.backend.convertWithOffsets +import org.jetbrains.kotlin.fir.backend.irOrigin import org.jetbrains.kotlin.fir.backend.isStubPropertyForPureField +import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.dispatchReceiverClassLookupTagOrNull import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride @@ -16,13 +19,13 @@ import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyProperty import org.jetbrains.kotlin.fir.lazy.Fir2IrLazySimpleFunction import org.jetbrains.kotlin.fir.originalForSubstitutionOverride +import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.symbols.Fir2IrPropertySymbol -import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin -import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent -import org.jetbrains.kotlin.ir.declarations.IrProperty -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbolInternals import org.jetbrains.kotlin.ir.util.IdSignature +import org.jetbrains.kotlin.utils.addToStdlib.runIf class Fir2IrLazyDeclarationsGenerator(val components: Fir2IrComponents) : Fir2IrComponents by components { internal fun createIrLazyFunction( @@ -87,4 +90,18 @@ class Fir2IrLazyDeclarationsGenerator(val components: Fir2IrComponents) : Fir2Ir return irProperty } + fun createIrLazyClass( + firClass: FirRegularClass, + irParent: IrDeclarationParent, + ): IrClass = firClass.convertWithOffsets { startOffset, endOffset -> + val firClassOrigin = firClass.irOrigin(session.firProvider) + val signature = runIf(configuration.linkViaSignatures) { + signatureComposer.composeSignature(firClass) + } + classifiersGenerator.declareIrClass(signature) { symbol -> + Fir2IrLazyClass(components, startOffset, endOffset, firClassOrigin, firClass, symbol).apply { + parent = irParent + } + } + } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt index 7fa2e10b8d7..649d76c49fb 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt @@ -191,11 +191,7 @@ class Fir2IrLazyProperty( }.apply { parent = this@Fir2IrLazyProperty.parent correspondingPropertySymbol = this@Fir2IrLazyProperty.symbol - with(classifierStorage) { - setTypeParameters( - this@Fir2IrLazyProperty.fir, ConversionTypeOrigin.DEFAULT - ) - } + classifiersGenerator.setTypeParameters(this, this@Fir2IrLazyProperty.fir, ConversionTypeOrigin.DEFAULT) } } @@ -222,11 +218,7 @@ class Fir2IrLazyProperty( ).apply { parent = this@Fir2IrLazyProperty.parent correspondingPropertySymbol = this@Fir2IrLazyProperty.symbol - with(classifierStorage) { - setTypeParameters( - this@Fir2IrLazyProperty.fir, ConversionTypeOrigin.SETTER - ) - } + classifiersGenerator.setTypeParameters(this, this@Fir2IrLazyProperty.fir, ConversionTypeOrigin.SETTER) } } }