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) - } - } }