[FIR2IR] Part 1. Cleanup Fir2IrClassifierStorage API (classes)

This commit cleans up API related to referencing classes and their symbols,
  to make it more similar with similar API in Fir2IrDeclarationStorage
This commit is contained in:
Dmitriy Novozhilov
2024-02-21 10:03:22 +02:00
committed by Space Team
parent 3bf0a11ced
commit 9c21c2214a
17 changed files with 90 additions and 84 deletions
@@ -21,7 +21,7 @@ class FirJvmBackendClassResolver(val components: Fir2IrComponents) : JvmBackendC
val symbol = components.session.symbolProvider.getClassLikeSymbolByClassId(type.classId) ?: return emptyList()
require(symbol is FirClassSymbol<*>)
return listOf(components.classifierStorage.getOrCreateIrClass(symbol).symbol.descriptor)
return listOf(components.classifierStorage.getIrClassSymbol(symbol).descriptor)
}
}
@@ -23,9 +23,10 @@ class FirJvmElementAwareStringTable(
private val localPoppedUpClasses: List<IrAttributeContainer>,
nameResolver: JvmNameResolver? = null
) : JvmStringTable(nameResolver), FirElementAwareStringTable {
override fun getLocalClassIdReplacement(firClass: FirClass): ClassId =
components.classifierStorage.getCachedIrClass(firClass)?.getLocalClassIdReplacement()
?: throw AssertionError("not a local class: ${firClass.symbol.classId}")
override fun getLocalClassIdReplacement(firClass: FirClass): ClassId {
// TODO: should call getCachedIrLocalClass, see KT-66018
return components.classifierStorage.getIrClass(firClass).getLocalClassIdReplacement()
}
private fun IrClass.getLocalClassIdReplacement(): ClassId {
// This convoluted implementation aims to reproduce K1 behaviour (see JvmCodegenStringTable::getLocalClassIdReplacement).
@@ -188,7 +188,7 @@ fun FirClassifierSymbol<*>.toSymbol(
}
is FirClassSymbol -> {
classifierStorage.getOrCreateIrClass(this).symbol
classifierStorage.getIrClassSymbol(this)
}
else -> error("Unknown symbol: $this")
@@ -914,4 +914,4 @@ val incOrDeclSourceKindToIrStatementOrigin = mapOf(
KtFakeSourceElementKind.DesugaredPostfixDec to IrStatementOrigin.POSTFIX_DECR,
KtFakeSourceElementKind.DesugaredPrefixIncSecondGetReference to IrStatementOrigin.PREFIX_INCR,
KtFakeSourceElementKind.DesugaredPrefixDecSecondGetReference to IrStatementOrigin.PREFIX_DECR
)
)
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.backend.generators.isExternalParent
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression
@@ -26,13 +27,14 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.utils.addToStdlib.runIf
class Fir2IrClassifierStorage(
private val components: Fir2IrComponents,
commonMemberStorage: Fir2IrCommonMemberStorage,
private val conversionScope: Fir2IrConversionScope,
) : Fir2IrComponents by components {
private val classCache: MutableMap<FirRegularClass, IrClass> = commonMemberStorage.classCache
private val classCache: MutableMap<FirRegularClass, IrClassSymbol> = commonMemberStorage.classCache
private val typeAliasCache: MutableMap<FirTypeAlias, IrTypeAlias> = mutableMapOf()
@@ -61,7 +63,7 @@ class Fir2IrClassifierStorage(
*/
@DelicateDeclarationStorageApi
fun forEachCachedDeclarationSymbol(block: (IrSymbol) -> Unit) {
classCache.values.forEach { block(it.symbol) }
classCache.values.forEach { block(it) }
typeAliasCache.values.forEach { block(it.symbol) }
enumEntryCache.values.forEach { block(it.symbol) }
fieldsForContextReceivers.values.forEach { fields ->
@@ -195,58 +197,62 @@ class Fir2IrClassifierStorage(
if (regularClass.visibility == Visibilities.Local) {
localStorage[regularClass] = irClass
} else {
classCache[regularClass] = irClass
classCache[regularClass] = irClass.symbol
}
}
fun getCachedIrClass(klass: FirClass): IrClass? {
return if (klass is FirAnonymousObject || klass is FirRegularClass && klass.visibility == Visibilities.Local) {
localStorage[klass]
} else {
classCache[klass]
}
}
fun findIrClass(lookupTag: ConeClassLikeLookupTag): IrClass? {
return if (lookupTag.classId.isLocal) {
getCachedLocalClass(lookupTag)
} else {
val firSymbol = lookupTag.toSymbol(session)
if (firSymbol is FirClassSymbol) {
getOrCreateIrClass(firSymbol)
} else {
null
}
}
}
private fun getCachedLocalClass(lookupTag: ConeClassLikeLookupTag): IrClass? {
return localStorage[lookupTag.toSymbol(session)!!.fir as FirClass]
}
fun getOrCreateIrClass(firClassSymbol: FirClassSymbol<*>): IrClass {
val firClass = firClassSymbol.fir
classifierStorage.getCachedIrClass(firClass)?.let { return it }
/**
* FIR2IR looks over all non-local source classes and creates IR for them using [createAndCacheIrClass]
* This means that after this phase all classes are either created and bound to their symbols or external classes,
* which are created and bound at the first access anyway
*
* So, unlike callable declarations, it's safe to expose an API, which returns not just IrClassSymbol, but IrClass itself
*
* But on the first FIR2IR stage this API should not be used
*/
fun getIrClass(firClass: FirClass): IrClass {
getCachedIrClass(firClass)?.let { return it }
if (firClass is FirAnonymousObject || firClass is FirRegularClass && firClass.visibility == Visibilities.Local) {
return createAndCacheLocalIrClassOnTheFly(firClass)
}
firClass as FirRegularClass
val classId = firClassSymbol.classId
require(firClass is FirRegularClass)
val symbol = createClassSymbol(signature = null)
val classId = firClass.symbol.classId
val parentId = classId.outerClassId
val parentClass = parentId?.let { session.symbolProvider.getClassLikeSymbolByClassId(it) }
val irParent = declarationStorage.findIrParent(classId.packageFqName, parentClass?.toLookupTag(), firClassSymbol, firClass.origin)!!
val irParent = declarationStorage.findIrParent(classId.packageFqName, parentClass?.toLookupTag(), firClass.symbol, 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 }
val symbol = createClassSymbol(signature = null)
classCache[firClass] = symbol
check(irParent.isExternalParent()) { "Source classes should be created separately before referencing" }
val irClass = lazyDeclarationsGenerator.createIrLazyClass(firClass, irParent, symbol)
classCache[firClass] = irClass
// NB: this is needed to prevent recursions in case of self bounds
irClass.prepareTypeParameters()
return irClass
}
fun getIrClass(lookupTag: ConeClassLikeLookupTag): IrClass? {
val firClassSymbol = lookupTag.toSymbol(session) as? FirClassSymbol<*> ?: return null
return getIrClass(firClassSymbol.fir)
}
fun getCachedIrLocalClass(klass: FirClass): IrClass? {
return runIf(klass is FirAnonymousObject || klass is FirRegularClass && klass.visibility == Visibilities.Local) {
localStorage[klass]
}
}
private fun getCachedIrClass(klass: FirClass): IrClass? {
@OptIn(UnsafeDuringIrConstructionAPI::class)
return getCachedIrLocalClass(klass) ?: classCache[klass]?.owner
}
fun getIrClassSymbol(firClassSymbol: FirClassSymbol<*>): IrClassSymbol {
return getIrClass(firClassSymbol.fir).symbol
}
fun getIrClassSymbol(lookupTag: ConeClassLikeLookupTag): IrClassSymbol? {
return getIrClass(lookupTag)?.symbol
}
fun getFieldsWithContextReceiversForClass(irClass: IrClass, klass: FirClass): List<IrField> {
@@ -328,7 +334,7 @@ class Fir2IrClassifierStorage(
fun getIrAnonymousObjectForEnumEntry(anonymousObject: FirAnonymousObject, name: Name, irParent: IrClass?): IrClass {
localStorage[anonymousObject]?.let { return it }
val irAnonymousObject = classifierStorage.createAndCacheAnonymousObject(anonymousObject, Visibilities.Private, name, irParent)
val irAnonymousObject = createAndCacheAnonymousObject(anonymousObject, Visibilities.Private, name, irParent)
classifiersGenerator.processClassHeader(anonymousObject, irAnonymousObject)
return irAnonymousObject
}
@@ -26,7 +26,7 @@ class Fir2IrCommonMemberStorage(firMangler: FirMangler) {
val symbolTable = SymbolTable(signaturer = null, irFactory = IrFactoryImpl)
val classCache: MutableMap<FirRegularClass, IrClass> = mutableMapOf()
val classCache: MutableMap<FirRegularClass, IrClassSymbol> = mutableMapOf()
val typeParameterCache: MutableMap<FirTypeParameter, IrTypeParameter> = mutableMapOf()
@@ -434,13 +434,12 @@ class Fir2IrConverter(
private fun registerClassAndNestedClasses(klass: FirClass, parent: IrDeclarationParent): IrClass {
// Local classes might be referenced before they declared (see usages of Fir2IrClassifierStorage.createLocalIrClassOnTheFly)
// So, we only need to set its parent properly
val irClass =
classifierStorage.getCachedIrClass(klass)?.apply {
this.parent = parent
} ?: when (klass) {
is FirRegularClass -> classifierStorage.createAndCacheIrClass(klass, parent)
is FirAnonymousObject -> classifierStorage.createAndCacheAnonymousObject(klass, irParent = parent)
}
val irClass = classifierStorage.getCachedIrLocalClass(klass)?.apply {
this.parent = parent
} ?: when (klass) {
is FirRegularClass -> classifierStorage.createAndCacheIrClass(klass, parent)
is FirAnonymousObject -> classifierStorage.createAndCacheAnonymousObject(klass, irParent = parent)
}
registerNestedClasses(klass, irClass)
return irClass
}
@@ -463,7 +462,7 @@ class Fir2IrConverter(
private fun processClassAndNestedClassHeaders(klass: FirClass) {
classifiersGenerator.processClassHeader(klass)
processNestedClassHeaders(klass)
val irClass = classifierStorage.getCachedIrClass(klass)!!
val irClass = classifierStorage.getIrClass(klass)!!
/*
* This is needed to preserve the source order of declarations in the class
* IrClass should contain declarations in the source order, but creating of nested IrClass automatically adds created class to the list
@@ -522,7 +521,7 @@ class Fir2IrConverter(
val isInLocalClass = containingClass != null && (containingClass !is FirRegularClass || containingClass.isLocal)
when (declaration) {
is FirRegularClass -> {
val irClass = classifierStorage.getCachedIrClass(declaration)!!
val irClass = classifierStorage.getIrClass(declaration)!!
addDeclarationToParentIfNeeded(irClass)
processClassMembers(declaration, irClass)
}
@@ -410,7 +410,7 @@ class Fir2IrDeclarationStorage(
else -> shouldNotBeCalled()
}
requireNotNull(containingClassLookupTag) { "Containing class not found for ${callable.render()}"}
return classifierStorage.findIrClass(containingClassLookupTag)?.symbol
return classifierStorage.getIrClassSymbol(containingClassLookupTag)
?: error("IR class for $containingClassLookupTag not found")
}
@@ -994,7 +994,7 @@ class Fir2IrDeclarationStorage(
return when (val firDeclaration = firVariableSymbol.fir) {
is FirEnumEntry -> {
classifierStorage.getCachedIrEnumEntry(firDeclaration)?.let { return it.symbol }
val irParentClass = firDeclaration.containingClassLookupTag()?.let { classifierStorage.findIrClass(it) }!!
val irParentClass = firDeclaration.containingClassLookupTag()?.let { classifierStorage.getIrClass(it) }!!
val containingFile = firProvider.getFirCallableContainerFile(firVariableSymbol)
@@ -1247,9 +1247,9 @@ class Fir2IrDeclarationStorage(
}
private fun generateLazyFakeOverrides(name: Name, fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?) {
val firClassSymbol = fakeOverrideOwnerLookupTag?.toSymbol(session) as? FirClassSymbol
val firClassSymbol = fakeOverrideOwnerLookupTag?.toSymbol(session) as? FirClassSymbol<*>
if (firClassSymbol != null) {
val irClass = classifierStorage.getOrCreateIrClass(firClassSymbol)
val irClass = classifierStorage.getIrClass(firClassSymbol.fir)
if (irClass is Fir2IrLazyClass) {
irClass.getFakeOverridesByName(name)
}
@@ -1427,7 +1427,9 @@ class Fir2IrDeclarationStorage(
firOrigin: FirDeclarationOrigin
): IrDeclarationParent? {
if (parentLookupTag != null) {
return classifierStorage.findIrClass(parentLookupTag)
// At this point all source classes should be already created and bound to symbols
@OptIn(UnsafeDuringIrConstructionAPI::class)
return classifierStorage.getIrClassSymbol(parentLookupTag)?.owner
}
@@ -74,7 +74,7 @@ class Fir2IrPluginContext(
override fun referenceClass(classId: ClassId): IrClassSymbol? {
val firSymbol = symbolProvider.getClassLikeSymbolByClassId(classId) as? FirClassSymbol<*> ?: return null
return components.classifierStorage.getOrCreateIrClass(firSymbol).symbol
return components.classifierStorage.getIrClassSymbol(firSymbol)
}
override fun referenceTypeAlias(classId: ClassId): IrTypeAliasSymbol? {
@@ -191,7 +191,7 @@ class Fir2IrVisitor(
if (regularClass.visibility == Visibilities.Local) {
val irParent = conversionScope.parentFromStack()
// NB: for implicit types it is possible that local class is already cached
val irClass = classifierStorage.getCachedIrClass(regularClass)?.apply { this.parent = irParent }
val irClass = classifierStorage.getIrClass(regularClass)?.apply { this.parent = irParent }
if (irClass != null) {
conversionScope.withParent(irClass) {
memberGenerator.convertClassContent(irClass, regularClass)
@@ -200,7 +200,7 @@ class Fir2IrVisitor(
}
converter.processLocalClassAndNestedClasses(regularClass, irParent)
}
val irClass = classifierStorage.getCachedIrClass(regularClass)!!
val irClass = classifierStorage.getIrClass(regularClass)!!
if (regularClass.isSealed) {
irClass.sealedSubclasses = regularClass.getIrSymbolsForSealedSubclasses()
}
@@ -350,7 +350,7 @@ class Fir2IrVisitor(
) {
val irParent = conversionScope.parentFromStack()
// NB: for implicit types it is possible that anonymous object is already cached
val irAnonymousObject = classifierStorage.getCachedIrClass(anonymousObject)?.apply { this.parent = irParent }
val irAnonymousObject = classifierStorage.getCachedIrLocalClass(anonymousObject)?.apply { this.parent = irParent }
?: converter.processLocalClassAndNestedClasses(anonymousObject, irParent)
conversionScope.withParent(irAnonymousObject) {
@@ -711,7 +711,7 @@ class Fir2IrVisitor(
// We anyway can use 'else' branch as fallback, but
// this is an additional check of FIR2IR invariants
// (source classes should be already built when we analyze bodies)
classifierStorage.getCachedIrClass(firClass)!!.symbol
classifierStorage.getIrClass(firClass)!!.symbol
} else {
/*
* The only case when we can refer to non-source this is resolution to companion object of parent
@@ -729,7 +729,7 @@ class Fir2IrVisitor(
* val x: Int = foo() // this: Base.Companion
* ) : Base()
*/
classifierStorage.getOrCreateIrClass(firClassSymbol).symbol
classifierStorage.getIrClassSymbol(firClassSymbol)
}
if (firClass.classKind.isObject && shouldGenerateReceiverAsSingletonReference(irClassSymbol)) {
@@ -1560,7 +1560,7 @@ class Fir2IrVisitor(
is FirResolvedQualifier -> {
when (val symbol = argument.symbol) {
is FirClassSymbol -> {
classifierStorage.getOrCreateIrClass(symbol).symbol
classifierStorage.getIrClassSymbol(symbol)
}
is FirTypeAliasSymbol -> {
symbol.fir.fullyExpandedConeType(session).toIrClassSymbol()
@@ -1594,7 +1594,7 @@ class Fir2IrVisitor(
private fun ConeClassLikeType?.toIrClassSymbol(): IrClassSymbol? =
(this?.lookupTag?.toSymbol(session) as? FirClassSymbol<*>)?.let {
classifierStorage.getOrCreateIrClass(it).symbol
classifierStorage.getIrClassSymbol(it)
}
private fun convertToArrayLiteral(
@@ -92,7 +92,7 @@ class FirIrProvider(val components: Fir2IrComponents) : IrProvider {
val scope = with(components) { firClass.unsubstitutedScope() }
fun findIrClass(firClass: FirRegularClass): IrClass {
val irClassSymbol = classifierStorage.getOrCreateIrClass(firClass.symbol).symbol
val irClassSymbol = classifierStorage.getIrClassSymbol(firClass.symbol)
return getDeclaration(irClassSymbol) as IrClass
}
@@ -176,7 +176,7 @@ class FirIrProvider(val components: Fir2IrComponents) : IrProvider {
return when (kind) {
SymbolKind.CLASS_SYMBOL -> {
classifierStorage.getOrCreateIrClass((firDeclaration as FirRegularClass).symbol)
shouldNotBeCalled()
}
SymbolKind.ENUM_ENTRY_SYMBOL -> classifierStorage.getOrCreateIrEnumEntry(
firDeclaration as FirEnumEntry, parent as IrClass
@@ -596,7 +596,7 @@ class IrBuiltInsOverFir(
private fun loadClassSafe(classId: ClassId): IrClassSymbol? {
val firClassSymbol = symbolProvider.getClassLikeSymbolByClassId(classId) as? FirRegularClassSymbol ?: return null
return components.classifierStorage.getOrCreateIrClass(firClassSymbol).symbol
return components.classifierStorage.getIrClassSymbol(firClassSymbol)
}
@OptIn(UnsafeDuringIrConstructionAPI::class)
@@ -285,7 +285,7 @@ class CallAndReferenceGenerator(
val coneSuperType = superTypeRef.coneTypeSafe<ConeClassLikeType>() ?: return null
val firClassSymbol = coneSuperType.fullyExpandedType(session).lookupTag.toSymbol(session) as? FirClassSymbol<*>
if (firClassSymbol != null) {
return classifierStorage.getOrCreateIrClass(firClassSymbol).symbol
return classifierStorage.getIrClassSymbol(firClassSymbol)
}
return null
}
@@ -82,7 +82,7 @@ internal class ClassMemberGenerator(
declaration is FirConstructor && declaration.isPrimary -> {
}
declaration is FirRegularClass && declaration.visibility == Visibilities.Local -> {
val irNestedClass = classifierStorage.getCachedIrClass(declaration)!!
val irNestedClass = classifierStorage.getIrClass(declaration)
irNestedClass.parent = irClass
conversionScope.withParent(irNestedClass) {
convertClassContent(irNestedClass, declaration)
@@ -101,7 +101,7 @@ internal class ClassMemberGenerator(
dataClassMembersGenerator.generateBodiesForMultiFieldValueClassMembers(klass, irClass)
}
if (irClass.isData) {
dataClassMembersGenerator.generateBodiesForDataClassMembers(klass, irClass)
dataClassMembersGenerator.generateBodiesForDataClassMembers(klass, irClass)
}
}
@@ -337,7 +337,7 @@ class DelegatedMemberGenerator(private val components: Fir2IrComponents) : Fir2I
// dispatch receiver of the target method. Therefore, we need to check if a cast must be inserted.
val superFunctionDispatchReceiverType = originalFirDeclaration.dispatchReceiverType
val superFunctionDispatchReceiverLookupTag = (superFunctionDispatchReceiverType as? ConeClassLikeType)?.lookupTag
val superFunctionParentSymbol = superFunctionDispatchReceiverLookupTag?.let { classifierStorage.findIrClass(it)?.symbol }
val superFunctionParentSymbol = superFunctionDispatchReceiverLookupTag?.let { classifierStorage.getIrClassSymbol(it) }
dispatchReceiver = if (superFunctionParentSymbol == null || irField.type.isSubtypeOfClass(superFunctionParentSymbol)) {
getField
} else {
@@ -593,7 +593,7 @@ class FakeOverrideGenerator(
@OptIn(UnsafeDuringIrConstructionAPI::class)
val overriddenContainingIrClass =
declarationStorage.classifierStorage.getOrCreateIrClass(overriddenContainingClass.symbol).symbol.owner
declarationStorage.classifierStorage.getIrClassSymbol(overriddenContainingClass.symbol).owner
return superClasses.mapNotNull { superClass ->
if (superClass == overriddenContainingIrClass ||
@@ -733,9 +733,8 @@ internal fun FirSimpleFunction.generateOverriddenFunctionSymbols(containingClass
}
context(Fir2IrComponents)
@OptIn(UnsafeDuringIrConstructionAPI::class)
private fun FirClass.getSuperTypesAsIrClasses(): Set<IrClass> {
val irClass = declarationStorage.classifierStorage.getOrCreateIrClass(symbol)
@OptIn(UnsafeDuringIrConstructionAPI::class)
val irClass = declarationStorage.classifierStorage.getIrClassSymbol(symbol).owner
return irClass.superTypes.mapNotNull { it.classifierOrNull?.owner as? IrClass }.toSet()
}
@@ -108,7 +108,7 @@ class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrCompo
return irClass
}
fun processClassHeader(klass: FirClass, irClass: IrClass = classifierStorage.getCachedIrClass(klass)!!): IrClass {
fun processClassHeader(klass: FirClass, irClass: IrClass = classifierStorage.getIrClass(klass)): IrClass {
irClass.declareTypeParameters(klass)
irClass.setThisReceiver(klass.typeParameters)
irClass.declareSupertypes(klass)
@@ -221,8 +221,7 @@ class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrCompo
val irClass = if (classOrLocalParent === klass) {
result
} else {
classifierStorage.getCachedIrClass(klass)
?: error("Assuming that all nested classes of ${classOrLocalParent.classId.asString()} should already be cached")
classifierStorage.getIrClass(klass)
}
return LocalIrClassInfo(irClass, classOrLocalParent, result)
}
@@ -173,7 +173,7 @@ class Fir2IrLazyClass(
scope.processClassifiersByName(name) {
val declaration = it.fir as? FirRegularClass ?: return@processClassifiersByName
if (declaration.classId.outerClassId == fir.classId && shouldBuildStub(declaration)) {
result += classifierStorage.getOrCreateIrClass(declaration.symbol)
result += classifierStorage.getIrClassSymbol(declaration.symbol).owner
}
}
}