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 2d20b823071..032e55e6509 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 @@ -5,11 +5,15 @@ package org.jetbrains.kotlin.fir.backend -import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.declarations.utils.* +import org.jetbrains.kotlin.fir.declarations.utils.visibility import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression +import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass 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 @@ -19,8 +23,12 @@ 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.symbols.* -import org.jetbrains.kotlin.ir.symbols.impl.* +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrSymbol +import org.jetbrains.kotlin.ir.symbols.IrSymbolInternals +import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames @@ -49,6 +57,10 @@ class Fir2IrClassifierStorage( commonMemberStorage.localClassCache ) + private val localClassesCreatedOnTheFly: MutableMap = mutableMapOf() + + private var processMembersOfClassesOnTheFlyImmediately = false + private fun FirTypeRef.toIrType(typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT): IrType = with(typeConverter) { toIrType(typeOrigin) } @@ -268,7 +280,57 @@ class Fir2IrClassifierStorage( } fun getIrClassSymbol(firClassSymbol: FirClassSymbol<*>): IrClassSymbol { - return classifiersGenerator.createIrClassSymbolByFirSymbol(firClassSymbol) + 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( 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 6b30989be84..1575aaa770e 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) - classifiersGenerator.processMembersOfClassesCreatedOnTheFly() + classifierStorage.processMembersOfClassesCreatedOnTheFly() // 5. Body processing // If we encounter local class / anonymous object here, then we perform all (1)-(5) stages immediately 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 285f3bb8cdf..6a1f29e4dfc 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 @@ -14,12 +14,10 @@ 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.* @@ -34,10 +32,6 @@ 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, @@ -113,10 +107,15 @@ class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrCompo return false } - // TODO: it's worth to move this onTheFly stuff back to classifier storage + 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 - private fun createLocalIrClassOnTheFly(klass: FirClass): IrClass { + 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 -> @@ -132,35 +131,14 @@ class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrCompo if (processMembersOfClassesOnTheFlyImmediately) { converter.processClassMembers(classOrLocalParent, result) converter.bindFakeOverridesInClass(result) + } + val irClass = if (classOrLocalParent === klass) { + result } else { - localClassesCreatedOnTheFly[classOrLocalParent] = result + classifierStorage.getCachedIrClass(klass) + ?: error("Assuming that all nested classes of ${classOrLocalParent.classId.asString()} should already be cached") } - 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() + return LocalIrClassInfo(irClass, classOrLocalParent, result) } fun processClassHeader(klass: FirClass, irClass: IrClass = classifierStorage.getCachedIrClass(klass)!!): IrClass {