[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
|
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.*
|
||||||
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.expressions.FirAnonymousObjectExpression
|
||||||
|
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
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.providers.toSymbol
|
||||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
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.fir.types.toLookupTag
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.*
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.*
|
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.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
@@ -49,6 +57,10 @@ class Fir2IrClassifierStorage(
|
|||||||
commonMemberStorage.localClassCache
|
commonMemberStorage.localClassCache
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val localClassesCreatedOnTheFly: MutableMap<FirClass, IrClass> = mutableMapOf()
|
||||||
|
|
||||||
|
private var processMembersOfClassesOnTheFlyImmediately = false
|
||||||
|
|
||||||
private fun FirTypeRef.toIrType(typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT): IrType =
|
private fun FirTypeRef.toIrType(typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT): IrType =
|
||||||
with(typeConverter) { toIrType(typeOrigin) }
|
with(typeConverter) { toIrType(typeOrigin) }
|
||||||
|
|
||||||
@@ -268,7 +280,57 @@ class Fir2IrClassifierStorage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getIrClassSymbol(firClassSymbol: FirClassSymbol<*>): IrClassSymbol {
|
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(
|
fun getIrTypeParameterSymbol(
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class Fir2IrConverter(
|
|||||||
postponedDeclarationsForFakeOverridesBinding.clear()
|
postponedDeclarationsForFakeOverridesBinding.clear()
|
||||||
|
|
||||||
// Do (3) and (4) for local classes encountered during (3)
|
// Do (3) and (4) for local classes encountered during (3)
|
||||||
classifiersGenerator.processMembersOfClassesCreatedOnTheFly()
|
classifierStorage.processMembersOfClassesCreatedOnTheFly()
|
||||||
|
|
||||||
// 5. Body processing
|
// 5. Body processing
|
||||||
// If we encounter local class / anonymous object here, then we perform all (1)-(5) stages immediately
|
// 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.lazy.Fir2IrLazyClass
|
||||||
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
|
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
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.ConeClassLikeLookupTag
|
||||||
import org.jetbrains.kotlin.fir.symbols.Fir2IrClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.Fir2IrClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.Fir2IrEnumEntrySymbol
|
import org.jetbrains.kotlin.fir.symbols.Fir2IrEnumEntrySymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.Fir2IrTypeAliasSymbol
|
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.fir.types.toLookupTag
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
@@ -34,10 +32,6 @@ import org.jetbrains.kotlin.name.SpecialNames
|
|||||||
import org.jetbrains.kotlin.utils.addToStdlib.runUnless
|
import org.jetbrains.kotlin.utils.addToStdlib.runUnless
|
||||||
|
|
||||||
class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrComponents by components {
|
class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrComponents by components {
|
||||||
private val localClassesCreatedOnTheFly: MutableMap<FirClass, IrClass> = mutableMapOf()
|
|
||||||
|
|
||||||
private var processMembersOfClassesOnTheFlyImmediately = false
|
|
||||||
|
|
||||||
internal fun setTypeParameters(
|
internal fun setTypeParameters(
|
||||||
irOwner: IrTypeParametersContainer,
|
irOwner: IrTypeParametersContainer,
|
||||||
owner: FirTypeParameterRefsOwner,
|
owner: FirTypeParameterRefsOwner,
|
||||||
@@ -113,10 +107,15 @@ class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrCompo
|
|||||||
return false
|
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 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
|
// 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
|
// 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 ->
|
val classOrLocalParent = generateSequence(klass) { c ->
|
||||||
(c as? FirRegularClass)?.containingClassForLocalAttr?.let { lookupTag ->
|
(c as? FirRegularClass)?.containingClassForLocalAttr?.let { lookupTag ->
|
||||||
@@ -132,35 +131,14 @@ class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrCompo
|
|||||||
if (processMembersOfClassesOnTheFlyImmediately) {
|
if (processMembersOfClassesOnTheFlyImmediately) {
|
||||||
converter.processClassMembers(classOrLocalParent, result)
|
converter.processClassMembers(classOrLocalParent, result)
|
||||||
converter.bindFakeOverridesInClass(result)
|
converter.bindFakeOverridesInClass(result)
|
||||||
|
}
|
||||||
|
val irClass = if (classOrLocalParent === klass) {
|
||||||
|
result
|
||||||
} else {
|
} 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
|
return LocalIrClassInfo(irClass, classOrLocalParent, result)
|
||||||
else (classifierStorage.getCachedIrClass(klass)
|
|
||||||
?: error("Assuming that all nested classes of ${classOrLocalParent.classId.asString()} should already be cached"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: this function is called exactly once, right after Fir2IrConverter finished f/o binding for regular classes
|
|
||||||
fun processMembersOfClassesCreatedOnTheFly() {
|
|
||||||
// After the call of this function, members of local classes may be processed immediately
|
|
||||||
// Before the call it's not possible, because f/o binding for regular classes isn't done yet
|
|
||||||
processMembersOfClassesOnTheFlyImmediately = true
|
|
||||||
for ((klass, irClass) in localClassesCreatedOnTheFly) {
|
|
||||||
converter.processClassMembers(klass, irClass)
|
|
||||||
// See the problem from KT-57441
|
|
||||||
// class Wrapper {
|
|
||||||
// private val dummy = object: Bar {}
|
|
||||||
// private val bar = object: Bar by dummy {}
|
|
||||||
// }
|
|
||||||
// interface Bar {
|
|
||||||
// val foo: String
|
|
||||||
// get() = ""
|
|
||||||
// }
|
|
||||||
// When we are building bar.foo fake override, we should call dummy.foo,
|
|
||||||
// so we should have object : Bar.foo fake override to be built and bound.
|
|
||||||
converter.bindFakeOverridesInClass(irClass)
|
|
||||||
}
|
|
||||||
localClassesCreatedOnTheFly.clear()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun processClassHeader(klass: FirClass, irClass: IrClass = classifierStorage.getCachedIrClass(klass)!!): IrClass {
|
fun processClassHeader(klass: FirClass, irClass: IrClass = classifierStorage.getCachedIrClass(klass)!!): IrClass {
|
||||||
|
|||||||
Reference in New Issue
Block a user