[FIR2IR] Extract logic of IR declarations generation into separate component. Part 14
Decompose creation, processing, and caching local classes between classifier storage and classifiers generator
This commit is contained in:
committed by
Space Team
parent
41fa276022
commit
eb9c732527
+67
-5
@@ -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<FirClass, IrClass> = 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(
|
||||
|
||||
@@ -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
|
||||
|
||||
+13
-35
@@ -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<FirClass, IrClass> = 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 {
|
||||
|
||||
Reference in New Issue
Block a user