From b9fd78d906db2205f70505149a5770d8070dd048 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Tue, 29 Aug 2023 15:30:28 +0300 Subject: [PATCH] [FIR2IR] Extract logic of IR declarations generation into separate component. Part 16 Group methods of Fir2IrClassifierStorage and Fir2IrClassifiersGenerator by types of declarations they are working with. This commit contains nothing but just moving code in borders of the same file --- .../fir/backend/Fir2IrClassifierStorage.kt | 426 ++++++------ .../generators/Fir2IrClassifiersGenerator.kt | 621 +++++++++--------- 2 files changed, 537 insertions(+), 510 deletions(-) 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 032e55e6509..0a1952dfcc2 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 @@ -64,6 +64,8 @@ class Fir2IrClassifierStorage( private fun FirTypeRef.toIrType(typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT): IrType = with(typeConverter) { toIrType(typeOrigin) } + // ------------------------------------ preprocessing ------------------------------------ + @OptIn(IrSymbolInternals::class) fun preCacheBuiltinClasses() { for ((classId, irBuiltinSymbol) in typeConverter.classIdToSymbolMap) { @@ -85,8 +87,9 @@ class Fir2IrClassifierStorage( } } - // Note: declareTypeParameters should be called before! + // ------------------------------------ type parameters ------------------------------------ + // Note: declareTypeParameters should be called before! internal fun preCacheTypeParameters(owner: FirTypeParameterRefsOwner, irOwnerSymbol: IrSymbol) { for ((index, typeParameter) in owner.typeParameters.withIndex()) { val original = typeParameter.symbol.fir @@ -100,6 +103,18 @@ class Fir2IrClassifierStorage( } } + internal fun getIrTypeParameter( + typeParameter: FirTypeParameter, + index: Int, + ownerSymbol: IrSymbol, + typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT + ): IrTypeParameter { + getCachedIrTypeParameter(typeParameter, typeOrigin)?.let { return it } + val irTypeParameter = createAndCacheIrTypeParameter(typeParameter, index, ownerSymbol, typeOrigin) + classifiersGenerator.initializeTypeParameterBounds(typeParameter, irTypeParameter) + return irTypeParameter + } + private fun createAndCacheIrTypeParameter( typeParameter: FirTypeParameter, index: Int, @@ -116,102 +131,6 @@ class Fir2IrClassifierStorage( return irTypeParameter } - internal fun setTypeParameters( - irOwner: IrTypeParametersContainer, - owner: FirTypeParameterRefsOwner, - typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT - ) { - classifiersGenerator.setTypeParameters(irOwner, owner, typeOrigin) - } - - fun getFieldsWithContextReceiversForClass(irClass: IrClass, klass: FirClass): List { - if (klass !is FirRegularClass || klass.contextReceivers.isEmpty()) return emptyList() - - return fieldsForContextReceivers.getOrPut(irClass) { - klass.contextReceivers.withIndex().map { (index, contextReceiver) -> - components.irFactory.createField( - startOffset = UNDEFINED_OFFSET, - endOffset = UNDEFINED_OFFSET, - origin = IrDeclarationOrigin.FIELD_FOR_CLASS_CONTEXT_RECEIVER, - name = Name.identifier("contextReceiverField$index"), - visibility = DescriptorVisibilities.PRIVATE, - symbol = IrFieldSymbolImpl(), - type = contextReceiver.typeRef.toIrType(), - isFinal = true, - isStatic = false, - isExternal = false, - ).also { - it.parent = irClass - } - } - } - } - - fun getCachedIrClass(klass: FirClass): IrClass? { - return if (klass is FirAnonymousObject || klass is FirRegularClass && klass.visibility == Visibilities.Local) { - localStorage[klass] - } else { - classCache[klass] - } - } - - private fun getCachedLocalClass(lookupTag: ConeClassLikeLookupTag): IrClass? { - return localStorage[lookupTag.toSymbol(session)!!.fir as FirClass] - } - - fun getCachedIrCodeFragment(codeFragment: FirCodeFragment): IrClass? { - return codeFragmentCache[codeFragment] - } - - fun createAndCacheIrTypeAlias( - typeAlias: FirTypeAlias, - parent: IrDeclarationParent - ): IrTypeAlias { - return classifiersGenerator.createIrTypeAlias(typeAlias, parent).also { - typeAliasCache[typeAlias] = it - } - } - - internal fun getCachedTypeAlias(firTypeAlias: FirTypeAlias): IrTypeAlias? = typeAliasCache[firTypeAlias] - - fun createAndCacheIrClass( - regularClass: FirRegularClass, - parent: IrDeclarationParent, - predefinedOrigin: IrDeclarationOrigin? = null - ): IrClass { - return classifiersGenerator.createIrClass(regularClass, parent, predefinedOrigin).also { - if (regularClass.visibility == Visibilities.Local) { - localStorage[regularClass] = it - } else { - classCache[regularClass] = it - } - } - } - - fun createAndCacheAnonymousObject( - anonymousObject: FirAnonymousObject, - visibility: Visibility = Visibilities.Local, - name: Name = SpecialNames.NO_NAME_PROVIDED, - irParent: IrDeclarationParent? = null - ): IrClass { - return classifiersGenerator.createAnonymousObject(anonymousObject, visibility, name, irParent).also { - localStorage[anonymousObject] = it - } - } - - fun createAndCacheCodeFragmentClass(codeFragment: FirCodeFragment, containingFile: IrFile): IrClass { - return classifiersGenerator.createCodeFragmentClass(codeFragment, containingFile).also { - codeFragmentCache[codeFragment] = it - } - } - - fun getIrAnonymousObjectForEnumEntry(anonymousObject: FirAnonymousObject, name: Name, irParent: IrClass?): IrClass { - localStorage[anonymousObject]?.let { return it } - val irAnonymousObject = classifierStorage.createAndCacheAnonymousObject(anonymousObject, Visibilities.Private, name, irParent) - classifiersGenerator.processClassHeader(anonymousObject, irAnonymousObject) - return irAnonymousObject - } - internal fun getCachedIrTypeParameter( typeParameter: FirTypeParameter, typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT @@ -222,117 +141,6 @@ class Fir2IrClassifierStorage( typeParameterCache[typeParameter] } - internal fun getIrTypeParameter( - typeParameter: FirTypeParameter, - index: Int, - ownerSymbol: IrSymbol, - typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT - ): IrTypeParameter { - getCachedIrTypeParameter(typeParameter, typeOrigin)?.let { return it } - val irTypeParameter = createAndCacheIrTypeParameter(typeParameter, index, ownerSymbol, typeOrigin) - classifiersGenerator.initializeTypeParameterBounds(typeParameter, irTypeParameter) - return irTypeParameter - } - - fun putEnumEntryClassInScope(enumEntry: FirEnumEntry, correspondingClass: IrClass) { - localStorage[(enumEntry.initializer as FirAnonymousObjectExpression).anonymousObject] = correspondingClass - } - - internal fun getCachedIrEnumEntry(enumEntry: FirEnumEntry): IrEnumEntry? = enumEntryCache[enumEntry] - - fun getIrEnumEntry( - enumEntry: FirEnumEntry, - irParent: IrClass, - predefinedOrigin: IrDeclarationOrigin? = null, - ): IrEnumEntry { - getCachedIrEnumEntry(enumEntry)?.let { return it } - - val firProviderForEntry = enumEntry.moduleData.session.firProvider - val containingFile = firProviderForEntry.getFirCallableContainerFile(enumEntry.symbol) - - @Suppress("NAME_SHADOWING") - val predefinedOrigin = predefinedOrigin ?: if (containingFile != null) { - IrDeclarationOrigin.DEFINED - } else { - irParent.origin - } - return classifiersGenerator.createIrEnumEntry( - enumEntry, - irParent = irParent, - predefinedOrigin = predefinedOrigin - ).also { - enumEntryCache[enumEntry] = it - } - } - - @OptIn(IrSymbolInternals::class) - fun findIrClass(lookupTag: ConeClassLikeLookupTag): IrClass? { - return if (lookupTag.classId.isLocal) { - getCachedLocalClass(lookupTag) - } else { - val firSymbol = lookupTag.toSymbol(session) - if (firSymbol is FirClassSymbol) { - getIrClassSymbol(firSymbol).owner - } else { - null - } - } - } - - fun getIrClassSymbol(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 createAndCacheLocalIrClassOnTheFly(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 - } - - private fun createAndCacheLocalIrClassOnTheFly(klass: FirClass): IrClass { - val (irClass, firClassOrLocalParent, irClassOrLocalParent) = classifiersGenerator.createLocalIrClassOnTheFly(klass, processMembersOfClassesOnTheFlyImmediately) - if (!processMembersOfClassesOnTheFlyImmediately) { - localClassesCreatedOnTheFly[firClassOrLocalParent] = irClassOrLocalParent - } - return irClass - } - - // 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 getIrTypeParameterSymbol( firTypeParameterSymbol: FirTypeParameterSymbol, typeOrigin: ConversionTypeOrigin @@ -366,4 +174,206 @@ class Fir2IrClassifierStorage( }.symbol } + // ------------------------------------ classes ------------------------------------ + + fun createAndCacheIrClass( + regularClass: FirRegularClass, + parent: IrDeclarationParent, + predefinedOrigin: IrDeclarationOrigin? = null + ): IrClass { + return classifiersGenerator.createIrClass(regularClass, parent, predefinedOrigin).also { + if (regularClass.visibility == Visibilities.Local) { + localStorage[regularClass] = it + } else { + classCache[regularClass] = it + } + } + } + + fun getCachedIrClass(klass: FirClass): IrClass? { + return if (klass is FirAnonymousObject || klass is FirRegularClass && klass.visibility == Visibilities.Local) { + localStorage[klass] + } else { + classCache[klass] + } + } + + @OptIn(IrSymbolInternals::class) + fun findIrClass(lookupTag: ConeClassLikeLookupTag): IrClass? { + return if (lookupTag.classId.isLocal) { + getCachedLocalClass(lookupTag) + } else { + val firSymbol = lookupTag.toSymbol(session) + if (firSymbol is FirClassSymbol) { + getIrClassSymbol(firSymbol).owner + } else { + null + } + } + } + + private fun getCachedLocalClass(lookupTag: ConeClassLikeLookupTag): IrClass? { + return localStorage[lookupTag.toSymbol(session)!!.fir as FirClass] + } + + fun getIrClassSymbol(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 createAndCacheLocalIrClassOnTheFly(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 getFieldsWithContextReceiversForClass(irClass: IrClass, klass: FirClass): List { + if (klass !is FirRegularClass || klass.contextReceivers.isEmpty()) return emptyList() + + return fieldsForContextReceivers.getOrPut(irClass) { + klass.contextReceivers.withIndex().map { (index, contextReceiver) -> + components.irFactory.createField( + startOffset = UNDEFINED_OFFSET, + endOffset = UNDEFINED_OFFSET, + origin = IrDeclarationOrigin.FIELD_FOR_CLASS_CONTEXT_RECEIVER, + name = Name.identifier("contextReceiverField$index"), + visibility = DescriptorVisibilities.PRIVATE, + symbol = IrFieldSymbolImpl(), + type = contextReceiver.typeRef.toIrType(), + isFinal = true, + isStatic = false, + isExternal = false, + ).also { + it.parent = irClass + } + } + } + } + + // ------------------------------------ local classes ------------------------------------ + + private fun createAndCacheLocalIrClassOnTheFly(klass: FirClass): IrClass { + val (irClass, firClassOrLocalParent, irClassOrLocalParent) = classifiersGenerator.createLocalIrClassOnTheFly(klass, processMembersOfClassesOnTheFlyImmediately) + if (!processMembersOfClassesOnTheFlyImmediately) { + localClassesCreatedOnTheFly[firClassOrLocalParent] = irClassOrLocalParent + } + return irClass + } + + // 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() + } + + + // ------------------------------------ anonymous objects ------------------------------------ + + fun createAndCacheAnonymousObject( + anonymousObject: FirAnonymousObject, + visibility: Visibility = Visibilities.Local, + name: Name = SpecialNames.NO_NAME_PROVIDED, + irParent: IrDeclarationParent? = null + ): IrClass { + return classifiersGenerator.createAnonymousObject(anonymousObject, visibility, name, irParent).also { + localStorage[anonymousObject] = it + } + } + + fun getIrAnonymousObjectForEnumEntry(anonymousObject: FirAnonymousObject, name: Name, irParent: IrClass?): IrClass { + localStorage[anonymousObject]?.let { return it } + val irAnonymousObject = classifierStorage.createAndCacheAnonymousObject(anonymousObject, Visibilities.Private, name, irParent) + classifiersGenerator.processClassHeader(anonymousObject, irAnonymousObject) + return irAnonymousObject + } + + // ------------------------------------ enum entries ------------------------------------ + + fun putEnumEntryClassInScope(enumEntry: FirEnumEntry, correspondingClass: IrClass) { + localStorage[(enumEntry.initializer as FirAnonymousObjectExpression).anonymousObject] = correspondingClass + } + + internal fun getCachedIrEnumEntry(enumEntry: FirEnumEntry): IrEnumEntry? { + return enumEntryCache[enumEntry] + } + + fun getIrEnumEntry( + enumEntry: FirEnumEntry, + irParent: IrClass, + predefinedOrigin: IrDeclarationOrigin? = null, + ): IrEnumEntry { + getCachedIrEnumEntry(enumEntry)?.let { return it } + + val firProviderForEntry = enumEntry.moduleData.session.firProvider + val containingFile = firProviderForEntry.getFirCallableContainerFile(enumEntry.symbol) + + @Suppress("NAME_SHADOWING") + val predefinedOrigin = predefinedOrigin ?: if (containingFile != null) { + IrDeclarationOrigin.DEFINED + } else { + irParent.origin + } + return classifiersGenerator.createIrEnumEntry( + enumEntry, + irParent = irParent, + predefinedOrigin = predefinedOrigin + ).also { + enumEntryCache[enumEntry] = it + } + } + + + // ------------------------------------ typealiases ------------------------------------ + + fun createAndCacheIrTypeAlias( + typeAlias: FirTypeAlias, + parent: IrDeclarationParent + ): IrTypeAlias { + return classifiersGenerator.createIrTypeAlias(typeAlias, parent).also { + typeAliasCache[typeAlias] = it + } + } + + internal fun getCachedTypeAlias(firTypeAlias: FirTypeAlias): IrTypeAlias? = typeAliasCache[firTypeAlias] + + // ------------------------------------ code fragments ------------------------------------ + + fun getCachedIrCodeFragment(codeFragment: FirCodeFragment): IrClass? { + return codeFragmentCache[codeFragment] + } + + fun createAndCacheCodeFragmentClass(codeFragment: FirCodeFragment, containingFile: IrFile): IrClass { + return classifiersGenerator.createCodeFragmentClass(codeFragment, containingFile).also { + codeFragmentCache[codeFragment] = it + } + } } 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 index 0cd0306aff1..eb10ed93818 100644 --- 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 @@ -32,287 +32,7 @@ import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.utils.addToStdlib.runUnless class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrComponents by components { - 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 - } - - data class LocalIrClassInfo( - val irClass: IrClass, - val firClassOrLocalParent: FirClass, - val irClassOrLocalParent: IrClass, - ) - - // 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 - fun createLocalIrClassOnTheFly(klass: FirClass, processMembersOfClassesOnTheFlyImmediately: Boolean): LocalIrClassInfo { - // 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) - } - val irClass = if (classOrLocalParent === klass) { - result - } else { - classifierStorage.getCachedIrClass(klass) - ?: error("Assuming that all nested classes of ${classOrLocalParent.classId.asString()} should already be cached") - } - return LocalIrClassInfo(irClass, classOrLocalParent, result) - } - - 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 - } - } - 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 - 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 - } - 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) - } - } - } - return irClass - } - - fun initializeTypeParameterBounds(typeParameter: FirTypeParameter, irTypeParameter: IrTypeParameter) { - irTypeParameter.superTypes = typeParameter.bounds.map { it.toIrType() } - } + // ------------------------------------ type parameters ------------------------------------ fun createIrTypeParameterWithoutBounds( typeParameter: FirTypeParameter, @@ -376,6 +96,306 @@ class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrCompo return irTypeParameter } + fun initializeTypeParameterBounds(typeParameter: FirTypeParameter, irTypeParameter: IrTypeParameter) { + irTypeParameter.superTypes = typeParameter.bounds.map { it.toIrType() } + } + + // ------------------------------------ classes ------------------------------------ + + 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 + return irClass + } + + 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.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.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 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 + } + + // ------------------------------------ local classes ------------------------------------ + + data class LocalIrClassInfo( + val irClass: IrClass, + val firClassOrLocalParent: FirClass, + val irClassOrLocalParent: IrClass, + ) + + // 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 + fun createLocalIrClassOnTheFly(klass: FirClass, processMembersOfClassesOnTheFlyImmediately: Boolean): LocalIrClassInfo { + // 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) + } + val irClass = if (classOrLocalParent === klass) { + result + } else { + classifierStorage.getCachedIrClass(klass) + ?: error("Assuming that all nested classes of ${classOrLocalParent.classId.asString()} should already be cached") + } + return LocalIrClassInfo(irClass, classOrLocalParent, result) + } + + 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) + } + } + + // ------------------------------------ anonymous objects ------------------------------------ + + 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 + } + return irAnonymousObject + } + + // ------------------------------------ typealiases ------------------------------------ + + private fun declareIrTypeAlias(signature: IdSignature?, factory: (IrTypeAliasSymbol) -> IrTypeAlias): IrTypeAlias { + return 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 + } + } + irTypeAlias + } + } + + // ------------------------------------ code fragments ------------------------------------ + + 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) + } + } + } + return irClass + } + + // ------------------------------------ enum entries ------------------------------------ + private fun declareIrEnumEntry(signature: IdSignature?, factory: (IrEnumEntrySymbol) -> IrEnumEntry): IrEnumEntry { return if (signature == null) factory(IrEnumEntrySymbolImpl()) @@ -421,6 +441,24 @@ class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrCompo return initializer is FirAnonymousObjectExpression && initializer.anonymousObject.declarations.any { it !is FirConstructor } } + // ------------------------------------ utilities ------------------------------------ + + 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) } + } + } + } + } + @OptIn(IrSymbolInternals::class) fun createIrClassSymbolForNotFoundClass(classLikeLookupTag: ConeClassLikeLookupTag): IrClassSymbol { val classId = classLikeLookupTag.classId @@ -452,25 +490,4 @@ class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrCompo } } - 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) - } - } }