[FIR2IR] Extract separate classifier storage from declaration storage

This commit is contained in:
Mikhail Glukhikh
2020-03-13 09:49:12 +03:00
parent 95b77f6386
commit 175145ce4e
6 changed files with 455 additions and 390 deletions
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.fir.references.FirThisReference
import org.jetbrains.kotlin.fir.references.impl.FirPropertyFromParameterResolvedNamedReference import org.jetbrains.kotlin.fir.references.impl.FirPropertyFromParameterResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.SyntheticPropertySymbol import org.jetbrains.kotlin.fir.resolve.calls.SyntheticPropertySymbol
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.AccessorSymbol import org.jetbrains.kotlin.fir.symbols.AccessorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
@@ -70,28 +69,32 @@ class ConversionTypeContext internal constructor(
} }
} }
fun FirClassifierSymbol<*>.toIrSymbol( fun FirClassifierSymbol<*>.toSymbol(
session: FirSession, session: FirSession,
declarationStorage: Fir2IrDeclarationStorage, classifierStorage: Fir2IrClassifierStorage,
typeContext: ConversionTypeContext = ConversionTypeContext.DEFAULT typeContext: ConversionTypeContext = ConversionTypeContext.DEFAULT
): IrClassifierSymbol { ): IrClassifierSymbol {
return when (this) { return when (this) {
is FirTypeParameterSymbol -> { is FirTypeParameterSymbol -> {
declarationStorage.getIrTypeParameterSymbol(this, typeContext) classifierStorage.getIrTypeParameterSymbol(this, typeContext)
} }
is FirTypeAliasSymbol -> { is FirTypeAliasSymbol -> {
val typeAlias = fir val typeAlias = fir
val coneClassLikeType = (typeAlias.expandedTypeRef as FirResolvedTypeRef).type as ConeClassLikeType val coneClassLikeType = (typeAlias.expandedTypeRef as FirResolvedTypeRef).type as ConeClassLikeType
coneClassLikeType.lookupTag.toSymbol(session)!!.toIrSymbol(session, declarationStorage) coneClassLikeType.lookupTag.toSymbol(session)!!.toSymbol(session, classifierStorage)
} }
is FirClassSymbol -> { is FirClassSymbol -> {
declarationStorage.getIrClassSymbol(this) classifierStorage.getIrClassSymbol(this)
} }
else -> throw AssertionError("Should not be here: $this") else -> throw AssertionError("Should not be here: $this")
} }
} }
fun FirReference.toSymbol(declarationStorage: Fir2IrDeclarationStorage): IrSymbol? { fun FirReference.toSymbol(
session: FirSession,
classifierStorage: Fir2IrClassifierStorage,
declarationStorage: Fir2IrDeclarationStorage
): IrSymbol? {
return when (this) { return when (this) {
is FirResolvedNamedReference -> { is FirResolvedNamedReference -> {
when (val resolvedSymbol = resolvedSymbol) { when (val resolvedSymbol = resolvedSymbol) {
@@ -100,15 +103,18 @@ fun FirReference.toSymbol(declarationStorage: Fir2IrDeclarationStorage): IrSymbo
resolvedSymbol.overriddenSymbol?.takeIf { it.callableId == resolvedSymbol.callableId } ?: resolvedSymbol resolvedSymbol.overriddenSymbol?.takeIf { it.callableId == resolvedSymbol.callableId } ?: resolvedSymbol
originalCallableSymbol.toSymbol(declarationStorage) originalCallableSymbol.toSymbol(declarationStorage)
} }
is FirClassifierSymbol<*> -> {
resolvedSymbol.toSymbol(session, classifierStorage)
}
else -> { else -> {
resolvedSymbol.toSymbol(declarationStorage) throw AssertionError("Unknown symbol: $resolvedSymbol")
} }
} }
} }
is FirThisReference -> { is FirThisReference -> {
when (val boundSymbol = boundSymbol?.toSymbol(declarationStorage)) { when (val boundSymbol = boundSymbol) {
is IrClassSymbol -> boundSymbol.owner.thisReceiver?.symbol is FirClassSymbol<*> -> classifierStorage.getIrClassSymbol(boundSymbol).owner.thisReceiver?.symbol
is IrFunctionSymbol -> boundSymbol.owner.extensionReceiverParameter?.symbol is FirFunctionSymbol -> declarationStorage.getIrFunctionSymbol(boundSymbol).owner.extensionReceiverParameter?.symbol
else -> null else -> null
} }
} }
@@ -116,10 +122,11 @@ fun FirReference.toSymbol(declarationStorage: Fir2IrDeclarationStorage): IrSymbo
} }
} }
private fun AbstractFirBasedSymbol<*>.toSymbol(declarationStorage: Fir2IrDeclarationStorage): IrSymbol? = when (this) { private fun FirCallableSymbol<*>.toSymbol(declarationStorage: Fir2IrDeclarationStorage): IrSymbol? = when (this) {
is FirClassSymbol -> declarationStorage.getIrClassSymbol(this)
is FirFunctionSymbol<*> -> declarationStorage.getIrFunctionSymbol(this) is FirFunctionSymbol<*> -> declarationStorage.getIrFunctionSymbol(this)
is FirPropertySymbol -> if (fir.isLocal) declarationStorage.getIrValueSymbol(this) else declarationStorage.getIrPropertyOrFieldSymbol(this) is FirPropertySymbol -> {
if (fir.isLocal) declarationStorage.getIrValueSymbol(this) else declarationStorage.getIrPropertyOrFieldSymbol(this)
}
is FirFieldSymbol -> declarationStorage.getIrPropertyOrFieldSymbol(this) is FirFieldSymbol -> declarationStorage.getIrPropertyOrFieldSymbol(this)
is FirBackingFieldSymbol -> declarationStorage.getIrBackingFieldSymbol(this) is FirBackingFieldSymbol -> declarationStorage.getIrBackingFieldSymbol(this)
is FirDelegateFieldSymbol<*> -> declarationStorage.getIrBackingFieldSymbol(this) is FirDelegateFieldSymbol<*> -> declarationStorage.getIrBackingFieldSymbol(this)
@@ -0,0 +1,364 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.firProvider
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrEnumEntryImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.*
import org.jetbrains.kotlin.ir.expressions.impl.IrEnumConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.name.Name
class Fir2IrClassifierStorage(
session: FirSession,
private val irSymbolTable: SymbolTable
) {
private val firProvider = session.firProvider
private val classCache = mutableMapOf<FirRegularClass, IrClass>()
private val typeParameterCache = mutableMapOf<FirTypeParameter, IrTypeParameter>()
private val typeParameterCacheForSetter = mutableMapOf<FirTypeParameter, IrTypeParameter>()
private val enumEntryCache = mutableMapOf<FirEnumEntry, IrEnumEntry>()
private val localStorage = Fir2IrLocalStorage()
lateinit var typeConverter: Fir2IrTypeConverter
lateinit var declarationStorage: Fir2IrDeclarationStorage
private fun FirTypeRef.toIrType(typeContext: ConversionTypeContext = ConversionTypeContext.DEFAULT): IrType =
with(typeConverter) { toIrType(typeContext) }
internal fun IrDeclaration.declareThisReceiverParameter(
parent: IrDeclarationParent,
thisType: IrType,
thisOrigin: IrDeclarationOrigin,
startOffset: Int = this.startOffset,
endOffset: Int = this.endOffset
): IrValueParameter {
val receiverDescriptor = WrappedReceiverParameterDescriptor()
return irSymbolTable.declareValueParameter(
startOffset, endOffset, thisOrigin, receiverDescriptor, thisType
) { symbol ->
IrValueParameterImpl(
startOffset, endOffset, thisOrigin, symbol,
Name.special("<this>"), -1, thisType,
varargElementType = null, isCrossinline = false, isNoinline = false
).apply {
this.parent = parent
receiverDescriptor.bind(this)
}
}
}
private fun IrClass.setThisReceiver() {
irSymbolTable.enterScope(descriptor)
val typeArguments = this.typeParameters.map {
IrSimpleTypeImpl(it.symbol, false, emptyList(), emptyList())
}
thisReceiver = declareThisReceiverParameter(
parent = this,
thisType = IrSimpleTypeImpl(symbol, false, typeArguments, emptyList()),
thisOrigin = IrDeclarationOrigin.INSTANCE_RECEIVER
)
irSymbolTable.leaveScope(descriptor)
}
internal fun preCacheTypeParameters(owner: FirTypeParametersOwner) {
owner.typeParameters.mapIndexed { index, typeParameter ->
getIrTypeParameter(typeParameter, index)
if (owner is FirProperty && owner.isVar) {
getIrTypeParameter(typeParameter, index, ConversionTypeContext.DEFAULT.inSetter())
}
}
}
internal fun IrTypeParametersContainer.setTypeParameters(
owner: FirTypeParametersOwner,
typeContext: ConversionTypeContext = ConversionTypeContext.DEFAULT
) {
typeParameters = owner.typeParameters.mapIndexed { index, typeParameter ->
getIrTypeParameter(typeParameter, index, typeContext).apply { parent = this@setTypeParameters }
}
}
private fun IrClass.declareSupertypesAndTypeParameters(klass: FirClass<*>): IrClass {
if (klass is FirRegularClass) {
setTypeParameters(klass)
}
superTypes = klass.superTypeRefs.map { superTypeRef -> superTypeRef.toIrType() }
return this
}
fun getCachedIrClass(klass: FirClass<*>): IrClass? {
return if (klass is FirAnonymousObject || klass is FirRegularClass && klass.visibility == Visibilities.LOCAL) {
localStorage.getLocalClass(klass)
} else {
classCache[klass]
}
}
private fun FirRegularClass.enumClassModality(): Modality {
return when {
declarations.any { it is FirCallableMemberDeclaration<*> && it.modality == Modality.ABSTRACT } -> {
Modality.ABSTRACT
}
declarations.any { it is FirEnumEntry && it.initializer != null } -> {
Modality.OPEN
}
else -> {
Modality.FINAL
}
}
}
internal fun createIrClass(klass: FirClass<*>, parent: IrDeclarationParent? = null): IrClass {
// NB: klass can be either FirRegularClass or FirAnonymousObject
if (klass is FirAnonymousObject) {
return createIrAnonymousObject(klass, irParent = parent)
}
val regularClass = klass as FirRegularClass
val origin =
if (firProvider.getFirClassifierContainerFileIfAny(klass.symbol) != null) IrDeclarationOrigin.DEFINED
else IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB
val irClass = registerIrClass(regularClass, parent, origin)
processClassHeader(regularClass, irClass)
return irClass
}
fun processClassHeader(regularClass: FirRegularClass, irClass: IrClass = getCachedIrClass(regularClass)!!): IrClass {
irClass.declareSupertypesAndTypeParameters(regularClass)
irClass.setThisReceiver()
return irClass
}
fun registerIrClass(
regularClass: FirRegularClass,
parent: IrDeclarationParent? = null,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
): IrClass {
val descriptor = WrappedClassDescriptor()
val visibility = regularClass.visibility
val modality = if (regularClass.classKind == ClassKind.ENUM_CLASS) {
regularClass.enumClassModality()
} else {
regularClass.modality ?: Modality.FINAL
}
val irClass = regularClass.convertWithOffsets { startOffset, endOffset ->
irSymbolTable.declareClass(startOffset, endOffset, origin, descriptor, modality, visibility) { symbol ->
IrClassImpl(
startOffset,
endOffset,
origin,
symbol,
regularClass.name,
regularClass.classKind,
visibility,
modality,
isCompanion = regularClass.isCompanion,
isInner = regularClass.isInner,
isData = regularClass.isData,
isExternal = regularClass.isExternal,
isInline = regularClass.isInline,
isExpect = regularClass.isExpect,
isFun = false // TODO FirRegularClass.isFun
).apply {
descriptor.bind(this)
}
}
}
if (parent != null) {
irClass.parent = parent
}
if (regularClass.visibility == Visibilities.LOCAL) {
localStorage.putLocalClass(regularClass, irClass)
} else {
classCache[regularClass] = irClass
}
return irClass
}
fun createIrAnonymousObject(
anonymousObject: FirAnonymousObject,
visibility: Visibility = Visibilities.LOCAL,
name: Name = Name.special("<no name provided>"),
irParent: IrDeclarationParent? = null
): IrClass {
val descriptor = WrappedClassDescriptor()
val origin = IrDeclarationOrigin.DEFINED
val modality = Modality.FINAL
val result = anonymousObject.convertWithOffsets { startOffset, endOffset ->
irSymbolTable.declareClass(startOffset, endOffset, origin, descriptor, modality, visibility) { symbol ->
IrClassImpl(
startOffset, endOffset, origin, symbol, name,
// NB: for unknown reason, IR uses 'CLASS' kind for simple anonymous objects
anonymousObject.classKind.takeIf { it == ClassKind.ENUM_ENTRY } ?: ClassKind.CLASS,
visibility, modality,
isCompanion = false, isInner = false, isData = false,
isExternal = false, isInline = false, isExpect = false, isFun = false
).apply {
descriptor.bind(this)
setThisReceiver()
if (irParent != null) {
this.parent = irParent
}
}
}
}.declareSupertypesAndTypeParameters(anonymousObject)
localStorage.putLocalClass(anonymousObject, result)
return result
}
private fun getIrAnonymousObjectForEnumEntry(anonymousObject: FirAnonymousObject, name: Name, irParent: IrClass?): IrClass {
localStorage.getLocalClass(anonymousObject)?.let { return it }
return createIrAnonymousObject(anonymousObject, Visibilities.PRIVATE, name, irParent)
}
private fun getIrTypeParameter(
typeParameter: FirTypeParameter,
index: Int = -1,
typeContext: ConversionTypeContext = ConversionTypeContext.DEFAULT
): IrTypeParameter {
// Here transformation is a bit difficult because one FIR property type parameter
// can be transformed to two different type parameters: one for getter and another one for setter
val simpleCachedParameter = typeParameterCache[typeParameter]
if (simpleCachedParameter != null) {
if (typeContext.origin != ConversionTypeOrigin.SETTER) {
return simpleCachedParameter
}
if (index < 0) {
val parent = simpleCachedParameter.parent
if (parent !is IrSimpleFunction || parent.returnType == typeConverter.unitType) {
return simpleCachedParameter
}
}
}
if (typeContext.origin == ConversionTypeOrigin.SETTER) {
typeParameterCacheForSetter[typeParameter]?.let { return it }
}
return typeParameter.run {
// Yet I don't want to enable this requirement because it breaks some tests
// However, if we get here it *should* mean that type parameter index is given explicitly
// At this moment (20.02.2020) this requirement breaks 11/355 Fir2IrText tests
// require(index != -1)
val descriptor = WrappedTypeParameterDescriptor()
val origin = IrDeclarationOrigin.DEFINED
val irTypeParameter =
convertWithOffsets { startOffset, endOffset ->
irSymbolTable.declareGlobalTypeParameter(startOffset, endOffset, origin, descriptor) { symbol ->
IrTypeParameterImpl(
startOffset, endOffset, origin, symbol,
name, if (index < 0) 0 else index,
isReified,
variance
).apply {
descriptor.bind(this)
}
}
}
// Cache the type parameter BEFORE processing its bounds/supertypes, to properly handle recursive type bounds.
if (typeContext.origin == ConversionTypeOrigin.SETTER) {
typeParameterCacheForSetter[typeParameter] = irTypeParameter
} else {
typeParameterCache[typeParameter] = irTypeParameter
}
bounds.mapTo(irTypeParameter.superTypes) { it.toIrType() }
irTypeParameter
}
}
fun putEnumEntryClassInScope(enumEntry: FirEnumEntry, correspondingClass: IrClass) {
localStorage.putLocalClass(enumEntry.initializer as FirAnonymousObject, correspondingClass)
}
fun getCachedIrEnumEntry(enumEntry: FirEnumEntry): IrEnumEntry? = enumEntryCache[enumEntry]
fun createIrEnumEntry(
enumEntry: FirEnumEntry,
irParent: IrClass?,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
): IrEnumEntry {
return enumEntry.convertWithOffsets { startOffset, endOffset ->
val desc = WrappedEnumEntryDescriptor()
declarationStorage.enterScope(desc)
val result = irSymbolTable.declareEnumEntry(startOffset, endOffset, origin, desc) { symbol ->
IrEnumEntryImpl(
startOffset, endOffset, origin, symbol, enumEntry.name
).apply {
desc.bind(this)
val irType = enumEntry.returnTypeRef.toIrType()
if (irParent != null) {
this.parent = irParent
}
val initializer = enumEntry.initializer
if (initializer != null) {
initializer as FirAnonymousObject
val klass = getIrAnonymousObjectForEnumEntry(initializer, enumEntry.name, irParent)
this.correspondingClass = klass
} else if (irParent != null) {
this.initializerExpression = IrExpressionBodyImpl(
IrEnumConstructorCallImpl(startOffset, endOffset, irType, irParent.constructors.first().symbol)
)
}
}
}
declarationStorage.leaveScope(desc)
enumEntryCache[enumEntry] = result
result
}
}
fun getIrClassSymbol(firClassSymbol: FirClassSymbol<*>): IrClassSymbol {
val firClass = firClassSymbol.fir
getCachedIrClass(firClass)?.let { return irSymbolTable.referenceClass(it.descriptor) }
// TODO: remove all this code and change to unbound symbol creation
val irClass = createIrClass(firClass)
if (firClass is FirAnonymousObject || firClass is FirRegularClass && firClass.visibility == Visibilities.LOCAL) {
return irSymbolTable.referenceClass(irClass.descriptor)
}
val classId = firClassSymbol.classId
val parentId = classId.outerClassId
val irParent = declarationStorage.findIrParent(classId.packageFqName, parentId, firClassSymbol)
if (irParent != null) {
irClass.parent = irParent
}
if (irParent is IrExternalPackageFragment) {
declarationStorage.addDeclarationsToExternalClass(firClass as FirRegularClass, irClass)
}
return irSymbolTable.referenceClass(irClass.descriptor)
}
fun getIrTypeParameterSymbol(
firTypeParameterSymbol: FirTypeParameterSymbol,
typeContext: ConversionTypeContext
): IrTypeParameterSymbol {
// TODO: use cached type parameter here
val irTypeParameter = getIrTypeParameter(firTypeParameterSymbol.fir, typeContext = typeContext)
return irSymbolTable.referenceTypeParameter(irTypeParameter.descriptor)
}
}
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.psi2ir.PsiSourceManager
class Fir2IrConverter( class Fir2IrConverter(
private val moduleDescriptor: FirModuleDescriptor, private val moduleDescriptor: FirModuleDescriptor,
private val sourceManager: PsiSourceManager, private val sourceManager: PsiSourceManager,
private val classifierStorage: Fir2IrClassifierStorage,
private val declarationStorage: Fir2IrDeclarationStorage private val declarationStorage: Fir2IrDeclarationStorage
) { ) {
@@ -71,7 +72,7 @@ class Fir2IrConverter(
fun processAnonymousObjectMembers( fun processAnonymousObjectMembers(
anonymousObject: FirAnonymousObject, anonymousObject: FirAnonymousObject,
irClass: IrClass = declarationStorage.getCachedIrClass(anonymousObject)!! irClass: IrClass = classifierStorage.getCachedIrClass(anonymousObject)!!
): IrClass { ): IrClass {
anonymousObject.getPrimaryConstructorIfAny()?.let { anonymousObject.getPrimaryConstructorIfAny()?.let {
irClass.declarations += declarationStorage.createIrConstructor(it, irClass) irClass.declarations += declarationStorage.createIrConstructor(it, irClass)
@@ -89,7 +90,7 @@ class Fir2IrConverter(
private fun processClassMembers( private fun processClassMembers(
regularClass: FirRegularClass, regularClass: FirRegularClass,
irClass: IrClass = declarationStorage.getCachedIrClass(regularClass)!! irClass: IrClass = classifierStorage.getCachedIrClass(regularClass)!!
): IrClass { ): IrClass {
regularClass.getPrimaryConstructorIfAny()?.let { regularClass.getPrimaryConstructorIfAny()?.let {
irClass.declarations += declarationStorage.createIrConstructor(it, irClass) irClass.declarations += declarationStorage.createIrConstructor(it, irClass)
@@ -102,7 +103,7 @@ class Fir2IrConverter(
} }
private fun registerClassAndNestedClasses(regularClass: FirRegularClass, parent: IrDeclarationParent): IrClass { private fun registerClassAndNestedClasses(regularClass: FirRegularClass, parent: IrDeclarationParent): IrClass {
val irClass = declarationStorage.registerIrClass(regularClass, parent) val irClass = classifierStorage.registerIrClass(regularClass, parent)
regularClass.declarations.forEach { regularClass.declarations.forEach {
if (it is FirRegularClass) { if (it is FirRegularClass) {
registerClassAndNestedClasses(it, irClass) registerClassAndNestedClasses(it, irClass)
@@ -112,7 +113,7 @@ class Fir2IrConverter(
} }
private fun processClassAndNestedClassHeaders(regularClass: FirRegularClass) { private fun processClassAndNestedClassHeaders(regularClass: FirRegularClass) {
declarationStorage.processClassHeader(regularClass) classifierStorage.processClassHeader(regularClass)
regularClass.declarations.forEach { regularClass.declarations.forEach {
if (it is FirRegularClass) { if (it is FirRegularClass) {
processClassAndNestedClassHeaders(it) processClassAndNestedClassHeaders(it)
@@ -137,7 +138,7 @@ class Fir2IrConverter(
null null
} }
is FirEnumEntry -> { is FirEnumEntry -> {
declarationStorage.createIrEnumEntry(declaration, parent as IrClass) classifierStorage.createIrEnumEntry(declaration, parent as IrClass)
} }
is FirAnonymousInitializer -> { is FirAnonymousInitializer -> {
declarationStorage.createIrAnonymousInitializer(declaration, parent as IrClass) declarationStorage.createIrAnonymousInitializer(declaration, parent as IrClass)
@@ -169,12 +170,16 @@ class Fir2IrConverter(
val builtIns = IrBuiltIns(moduleDescriptor.builtIns, typeTranslator, signaturer, symbolTable) val builtIns = IrBuiltIns(moduleDescriptor.builtIns, typeTranslator, signaturer, symbolTable)
val sourceManager = PsiSourceManager() val sourceManager = PsiSourceManager()
val declarationStorage = Fir2IrDeclarationStorage(session, symbolTable, moduleDescriptor) val declarationStorage = Fir2IrDeclarationStorage(session, symbolTable, moduleDescriptor)
val typeConverter = Fir2IrTypeConverter(session, declarationStorage, builtIns) val classifierStorage = Fir2IrClassifierStorage(session, symbolTable)
val typeConverter = Fir2IrTypeConverter(session, classifierStorage, builtIns)
declarationStorage.typeConverter = typeConverter declarationStorage.typeConverter = typeConverter
classifierStorage.typeConverter = typeConverter
declarationStorage.classifierStorage = classifierStorage
classifierStorage.declarationStorage = declarationStorage
typeConverter.initBuiltinTypes() typeConverter.initBuiltinTypes()
val irFiles = mutableListOf<IrFile>() val irFiles = mutableListOf<IrFile>()
val converter = Fir2IrConverter(moduleDescriptor, sourceManager, declarationStorage) val converter = Fir2IrConverter(moduleDescriptor, sourceManager, classifierStorage, declarationStorage)
for (firFile in firFiles) { for (firFile in firFiles) {
converter.registerFileAndClasses(firFile) converter.registerFileAndClasses(firFile)
} }
@@ -186,7 +191,7 @@ class Fir2IrConverter(
} }
val fir2irVisitor = Fir2IrVisitor( val fir2irVisitor = Fir2IrVisitor(
session, symbolTable, declarationStorage, converter, typeConverter, builtIns, fakeOverrideMode session, symbolTable, classifierStorage, declarationStorage, converter, typeConverter, builtIns, fakeOverrideMode
) )
for (firFile in firFiles) { for (firFile in firFiles) {
val irFile = firFile.accept(fir2irVisitor, null) as IrFile val irFile = firFile.accept(fir2irVisitor, null) as IrFile
@@ -5,7 +5,9 @@
package org.jetbrains.kotlin.fir.backend package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
@@ -28,14 +30,11 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.descriptors.* import org.jetbrains.kotlin.ir.descriptors.*
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrEnumConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -56,12 +55,6 @@ class Fir2IrDeclarationStorage(
private val fileCache = mutableMapOf<FirFile, IrFile>() private val fileCache = mutableMapOf<FirFile, IrFile>()
private val classCache = mutableMapOf<FirRegularClass, IrClass>()
private val typeParameterCache = mutableMapOf<FirTypeParameter, IrTypeParameter>()
private val typeParameterCacheForSetter = mutableMapOf<FirTypeParameter, IrTypeParameter>()
private val functionCache = mutableMapOf<FirFunction<*>, IrSimpleFunction>() private val functionCache = mutableMapOf<FirFunction<*>, IrSimpleFunction>()
private val constructorCache = mutableMapOf<FirConstructor, IrConstructor>() private val constructorCache = mutableMapOf<FirConstructor, IrConstructor>()
@@ -72,12 +65,12 @@ class Fir2IrDeclarationStorage(
private val fieldCache = mutableMapOf<FirField, IrField>() private val fieldCache = mutableMapOf<FirField, IrField>()
private val enumEntryCache = mutableMapOf<FirEnumEntry, IrEnumEntry>()
private val localStorage = Fir2IrLocalStorage() private val localStorage = Fir2IrLocalStorage()
lateinit var typeConverter: Fir2IrTypeConverter lateinit var typeConverter: Fir2IrTypeConverter
lateinit var classifierStorage: Fir2IrClassifierStorage
fun registerFile(firFile: FirFile, irFile: IrFile) { fun registerFile(firFile: FirFile, irFile: IrFile) {
fileCache[firFile] = irFile fileCache[firFile] = irFile
} }
@@ -121,68 +114,7 @@ class Fir2IrDeclarationStorage(
} }
} }
private fun IrDeclaration.declareThisReceiverParameter( internal fun addDeclarationsToExternalClass(regularClass: FirRegularClass, irClass: IrClass) {
parent: IrDeclarationParent,
thisType: IrType,
thisOrigin: IrDeclarationOrigin,
startOffset: Int = this.startOffset,
endOffset: Int = this.endOffset
): IrValueParameter {
val receiverDescriptor = WrappedReceiverParameterDescriptor()
return irSymbolTable.declareValueParameter(
startOffset, endOffset, thisOrigin, receiverDescriptor, thisType
) { symbol ->
IrValueParameterImpl(
startOffset, endOffset, thisOrigin, symbol,
Name.special("<this>"), -1, thisType,
varargElementType = null, isCrossinline = false, isNoinline = false
).apply {
this.parent = parent
receiverDescriptor.bind(this)
}
}
}
private fun IrClass.setThisReceiver() {
enterScope(descriptor)
val typeArguments = this.typeParameters.map {
IrSimpleTypeImpl(it.symbol, false, emptyList(), emptyList())
}
thisReceiver = declareThisReceiverParameter(
parent = this,
thisType = IrSimpleTypeImpl(symbol, false, typeArguments, emptyList()),
thisOrigin = IrDeclarationOrigin.INSTANCE_RECEIVER
)
leaveScope(descriptor)
}
private fun preCacheTypeParameters(owner: FirTypeParametersOwner) {
owner.typeParameters.mapIndexed { index, typeParameter ->
getIrTypeParameter(typeParameter, index)
if (owner is FirProperty && owner.isVar) {
getIrTypeParameter(typeParameter, index, ConversionTypeContext.DEFAULT.inSetter())
}
}
}
private fun IrTypeParametersContainer.setTypeParameters(
owner: FirTypeParametersOwner,
typeContext: ConversionTypeContext = ConversionTypeContext.DEFAULT
) {
typeParameters = owner.typeParameters.mapIndexed { index, typeParameter ->
getIrTypeParameter(typeParameter, index, typeContext).apply { parent = this@setTypeParameters }
}
}
private fun IrClass.declareSupertypesAndTypeParameters(klass: FirClass<*>): IrClass {
if (klass is FirRegularClass) {
setTypeParameters(klass)
}
superTypes = klass.superTypeRefs.map { superTypeRef -> superTypeRef.toIrType() }
return this
}
private fun addDeclarationsToExternalClass(regularClass: FirRegularClass, irClass: IrClass) {
if (regularClass.symbol.classId.packageFqName.startsWith(Name.identifier("kotlin"))) { if (regularClass.symbol.classId.packageFqName.startsWith(Name.identifier("kotlin"))) {
// Note: yet this is necessary only for *Range / *Progression classes // Note: yet this is necessary only for *Range / *Progression classes
// due to BE optimizations (for lowering) that use their first / last / step members // due to BE optimizations (for lowering) that use their first / last / step members
@@ -202,7 +134,7 @@ class Fir2IrDeclarationStorage(
createIrConstructor(declaration, irClass) createIrConstructor(declaration, irClass)
} }
is FirRegularClass -> { is FirRegularClass -> {
createIrClass(declaration, irClass) classifierStorage.createIrClass(declaration, irClass)
} }
else -> continue else -> continue
} }
@@ -235,190 +167,12 @@ class Fir2IrDeclarationStorage(
} }
} }
fun getCachedIrClass(klass: FirClass<*>): IrClass? { internal fun findIrParent(packageFqName: FqName, parentClassId: ClassId?, firBasedSymbol: FirBasedSymbol<*>): IrDeclarationParent? {
return if (klass is FirAnonymousObject || klass is FirRegularClass && klass.visibility == Visibilities.LOCAL) {
localStorage.getLocalClass(klass)
} else {
classCache[klass]
}
}
private fun FirRegularClass.enumClassModality(): Modality {
return when {
declarations.any { it is FirCallableMemberDeclaration<*> && it.modality == Modality.ABSTRACT } -> {
Modality.ABSTRACT
}
declarations.any { it is FirEnumEntry && it.initializer != null } -> {
Modality.OPEN
}
else -> {
Modality.FINAL
}
}
}
private fun createIrClass(klass: FirClass<*>, parent: IrDeclarationParent? = null): IrClass {
// NB: klass can be either FirRegularClass or FirAnonymousObject
if (klass is FirAnonymousObject) {
return createIrAnonymousObject(klass, irParent = parent)
}
val regularClass = klass as FirRegularClass
val origin =
if (firProvider.getFirClassifierContainerFileIfAny(klass.symbol) != null) IrDeclarationOrigin.DEFINED
else IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB
val irClass = registerIrClass(regularClass, parent, origin)
processClassHeader(regularClass, irClass)
return irClass
}
fun processClassHeader(regularClass: FirRegularClass, irClass: IrClass = getCachedIrClass(regularClass)!!): IrClass {
irClass.declareSupertypesAndTypeParameters(regularClass)
irClass.setThisReceiver()
return irClass
}
fun registerIrClass(
regularClass: FirRegularClass,
parent: IrDeclarationParent? = null,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
): IrClass {
val descriptor = WrappedClassDescriptor()
val visibility = regularClass.visibility
val modality = if (regularClass.classKind == ClassKind.ENUM_CLASS) {
regularClass.enumClassModality()
} else {
regularClass.modality ?: Modality.FINAL
}
val irClass = regularClass.convertWithOffsets { startOffset, endOffset ->
irSymbolTable.declareClass(startOffset, endOffset, origin, descriptor, modality, visibility) { symbol ->
IrClassImpl(
startOffset,
endOffset,
origin,
symbol,
regularClass.name,
regularClass.classKind,
visibility,
modality,
isCompanion = regularClass.isCompanion,
isInner = regularClass.isInner,
isData = regularClass.isData,
isExternal = regularClass.isExternal,
isInline = regularClass.isInline,
isExpect = regularClass.isExpect,
isFun = false // TODO FirRegularClass.isFun
).apply {
descriptor.bind(this)
}
}
}
if (parent != null) {
irClass.parent = parent
}
if (regularClass.visibility == Visibilities.LOCAL) {
localStorage.putLocalClass(regularClass, irClass)
} else {
classCache[regularClass] = irClass
}
return irClass
}
fun createIrAnonymousObject(
anonymousObject: FirAnonymousObject,
visibility: Visibility = Visibilities.LOCAL,
name: Name = Name.special("<no name provided>"),
irParent: IrDeclarationParent? = null
): IrClass {
val descriptor = WrappedClassDescriptor()
val origin = IrDeclarationOrigin.DEFINED
val modality = Modality.FINAL
val result = anonymousObject.convertWithOffsets { startOffset, endOffset ->
irSymbolTable.declareClass(startOffset, endOffset, origin, descriptor, modality, visibility) { symbol ->
IrClassImpl(
startOffset, endOffset, origin, symbol, name,
// NB: for unknown reason, IR uses 'CLASS' kind for simple anonymous objects
anonymousObject.classKind.takeIf { it == ClassKind.ENUM_ENTRY } ?: ClassKind.CLASS,
visibility, modality,
isCompanion = false, isInner = false, isData = false,
isExternal = false, isInline = false, isExpect = false, isFun = false
).apply {
descriptor.bind(this)
setThisReceiver()
if (irParent != null) {
this.parent = irParent
}
}
}
}.declareSupertypesAndTypeParameters(anonymousObject)
localStorage.putLocalClass(anonymousObject, result)
return result
}
private fun getIrAnonymousObjectForEnumEntry(anonymousObject: FirAnonymousObject, name: Name, irParent: IrClass?): IrClass {
localStorage.getLocalClass(anonymousObject)?.let { return it }
return createIrAnonymousObject(anonymousObject, Visibilities.PRIVATE, name, irParent)
}
private fun getIrTypeParameter(
typeParameter: FirTypeParameter,
index: Int = -1,
typeContext: ConversionTypeContext = ConversionTypeContext.DEFAULT
): IrTypeParameter {
// Here transformation is a bit difficult because one FIR property type parameter
// can be transformed to two different type parameters: one for getter and another one for setter
val simpleCachedParameter = typeParameterCache[typeParameter]
if (simpleCachedParameter != null) {
if (typeContext.origin != ConversionTypeOrigin.SETTER) {
return simpleCachedParameter
}
if (index < 0) {
val parent = simpleCachedParameter.parent
if (parent !is IrSimpleFunction || parent.returnType == typeConverter.unitType) {
return simpleCachedParameter
}
}
}
if (typeContext.origin == ConversionTypeOrigin.SETTER) {
typeParameterCacheForSetter[typeParameter]?.let { return it }
}
return typeParameter.run {
// Yet I don't want to enable this requirement because it breaks some tests
// However, if we get here it *should* mean that type parameter index is given explicitly
// At this moment (20.02.2020) this requirement breaks 11/355 Fir2IrText tests
// require(index != -1)
val descriptor = WrappedTypeParameterDescriptor()
val origin = IrDeclarationOrigin.DEFINED
val irTypeParameter =
convertWithOffsets { startOffset, endOffset ->
irSymbolTable.declareGlobalTypeParameter(startOffset, endOffset, origin, descriptor) { symbol ->
IrTypeParameterImpl(
startOffset, endOffset, origin, symbol,
name, if (index < 0) 0 else index,
isReified,
variance
).apply {
descriptor.bind(this)
}
}
}
// Cache the type parameter BEFORE processing its bounds/supertypes, to properly handle recursive type bounds.
if (typeContext.origin == ConversionTypeOrigin.SETTER) {
typeParameterCacheForSetter[typeParameter] = irTypeParameter
} else {
typeParameterCache[typeParameter] = irTypeParameter
}
bounds.mapTo(irTypeParameter.superTypes) { it.toIrType() }
irTypeParameter
}
}
private fun findIrParent(packageFqName: FqName, parentClassId: ClassId?, firBasedSymbol: FirBasedSymbol<*>): IrDeclarationParent? {
return if (parentClassId != null) { return if (parentClassId != null) {
// TODO: this will never work for local classes // TODO: this will never work for local classes
val parentFirSymbol = firSymbolProvider.getClassLikeSymbolByFqName(parentClassId) val parentFirSymbol = firSymbolProvider.getClassLikeSymbolByFqName(parentClassId)
if (parentFirSymbol is FirClassSymbol) { if (parentFirSymbol is FirClassSymbol) {
val parentIrSymbol = getIrClassSymbol(parentFirSymbol) val parentIrSymbol = classifierStorage.getIrClassSymbol(parentFirSymbol)
parentIrSymbol.owner parentIrSymbol.owner
} else { } else {
null null
@@ -485,7 +239,9 @@ class Fir2IrDeclarationStorage(
) { ) {
val parent = this val parent = this
if (function is FirSimpleFunction) { if (function is FirSimpleFunction) {
setTypeParameters(function) with(classifierStorage) {
setTypeParameters(function)
}
} }
val forSetter = function is FirPropertyAccessor && function.isSetter val forSetter = function is FirPropertyAccessor && function.isSetter
val typeContext = ConversionTypeContext( val typeContext = ConversionTypeContext(
@@ -509,24 +265,26 @@ class Fir2IrDeclarationStorage(
if (function !is FirConstructor) { if (function !is FirConstructor) {
val thisOrigin = IrDeclarationOrigin.DEFINED val thisOrigin = IrDeclarationOrigin.DEFINED
val receiverTypeRef = if (function !is FirPropertyAccessor) function?.receiverTypeRef else parentPropertyReceiverType val receiverTypeRef = if (function !is FirPropertyAccessor) function?.receiverTypeRef else parentPropertyReceiverType
if (receiverTypeRef != null) { with(classifierStorage) {
extensionReceiverParameter = receiverTypeRef.convertWithOffsets { startOffset, endOffset -> if (receiverTypeRef != null) {
declareThisReceiverParameter( extensionReceiverParameter = receiverTypeRef.convertWithOffsets { startOffset, endOffset ->
declareThisReceiverParameter(
parent,
thisType = receiverTypeRef.toIrType(typeContext),
thisOrigin = thisOrigin,
startOffset = startOffset,
endOffset = endOffset
)
}
}
if (function !is FirAnonymousFunction && containingClass != null && !isStatic) {
dispatchReceiverParameter = declareThisReceiverParameter(
parent, parent,
thisType = receiverTypeRef.toIrType(typeContext), thisType = containingClass.thisReceiver!!.type,
thisOrigin = thisOrigin, thisOrigin = thisOrigin
startOffset = startOffset,
endOffset = endOffset
) )
} }
} }
if (function !is FirAnonymousFunction && containingClass != null && !isStatic) {
dispatchReceiverParameter = declareThisReceiverParameter(
parent,
thisType = containingClass.thisReceiver!!.type,
thisOrigin = thisOrigin
)
}
} }
} }
@@ -552,10 +310,6 @@ class Fir2IrDeclarationStorage(
return this return this
} }
fun putEnumEntryClassInScope(enumEntry: FirEnumEntry, correspondingClass: IrClass) {
localStorage.putLocalClass(enumEntry.initializer as FirAnonymousObject, correspondingClass)
}
fun getCachedIrFunction(function: FirFunction<*>): IrSimpleFunction? { fun getCachedIrFunction(function: FirFunction<*>): IrSimpleFunction? {
return if (function !is FirSimpleFunction || function.visibility == Visibilities.LOCAL) { return if (function !is FirSimpleFunction || function.visibility == Visibilities.LOCAL) {
localStorage.getLocalFunction(function) localStorage.getLocalFunction(function)
@@ -578,7 +332,7 @@ class Fir2IrDeclarationStorage(
function.symbol.callableId.isKFunctionInvoke() -> IrDeclarationOrigin.FAKE_OVERRIDE function.symbol.callableId.isKFunctionInvoke() -> IrDeclarationOrigin.FAKE_OVERRIDE
else -> origin else -> origin
} }
preCacheTypeParameters(function) classifierStorage.preCacheTypeParameters(function)
val name = simpleFunction?.name val name = simpleFunction?.name
?: if (isLambda) Name.special("<anonymous>") else Name.special("<no name provided>") ?: if (isLambda) Name.special("<anonymous>") else Name.special("<no name provided>")
val visibility = simpleFunction?.visibility ?: Visibilities.LOCAL val visibility = simpleFunction?.visibility ?: Visibilities.LOCAL
@@ -694,12 +448,14 @@ class Fir2IrDeclarationStorage(
isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE, isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE,
isOperator = false isOperator = false
).apply { ).apply {
setTypeParameters( with(classifierStorage) {
property, ConversionTypeContext( setTypeParameters(
definitelyNotNull = false, property, ConversionTypeContext(
origin = if (isSetter) ConversionTypeOrigin.SETTER else ConversionTypeOrigin.DEFAULT definitelyNotNull = false,
origin = if (isSetter) ConversionTypeOrigin.SETTER else ConversionTypeOrigin.DEFAULT
)
) )
) }
if (propertyAccessor == null && isSetter) { if (propertyAccessor == null && isSetter) {
declareDefaultSetterParameter( declareDefaultSetterParameter(
property.returnTypeRef.toIrType(ConversionTypeContext.DEFAULT.inSetter()) property.returnTypeRef.toIrType(ConversionTypeContext.DEFAULT.inSetter())
@@ -719,44 +475,6 @@ class Fir2IrDeclarationStorage(
} }
} }
fun getCachedIrEnumEntry(enumEntry: FirEnumEntry): IrEnumEntry? = enumEntryCache[enumEntry]
fun createIrEnumEntry(
enumEntry: FirEnumEntry,
irParent: IrClass?,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
): IrEnumEntry {
return enumEntry.convertWithOffsets { startOffset, endOffset ->
val desc = WrappedEnumEntryDescriptor()
enterScope(desc)
val result = irSymbolTable.declareEnumEntry(startOffset, endOffset, origin, desc) { symbol ->
IrEnumEntryImpl(
startOffset, endOffset, origin, symbol, enumEntry.name
).apply {
desc.bind(this)
val irType = enumEntry.returnTypeRef.toIrType()
if (irParent != null) {
this.parent = irParent
}
val initializer = enumEntry.initializer
if (initializer != null) {
initializer as FirAnonymousObject
val klass = getIrAnonymousObjectForEnumEntry(initializer, enumEntry.name, irParent)
this.correspondingClass = klass
} else if (irParent != null) {
this.initializerExpression = IrExpressionBodyImpl(
IrEnumConstructorCallImpl(startOffset, endOffset, irType, irParent.constructors.first().symbol)
)
}
}
}
leaveScope(desc)
enumEntryCache[enumEntry] = result
result
}
}
fun createIrProperty( fun createIrProperty(
property: FirProperty, property: FirProperty,
irParent: IrDeclarationParent?, irParent: IrDeclarationParent?,
@@ -764,7 +482,7 @@ class Fir2IrDeclarationStorage(
): IrProperty { ): IrProperty {
val containerSource = property.containerSource val containerSource = property.containerSource
val descriptor = containerSource?.let { WrappedPropertyDescriptorWithContainerSource(it) } ?: WrappedPropertyDescriptor() val descriptor = containerSource?.let { WrappedPropertyDescriptorWithContainerSource(it) } ?: WrappedPropertyDescriptor()
preCacheTypeParameters(property) classifierStorage.preCacheTypeParameters(property)
return property.convertWithOffsets { startOffset, endOffset -> return property.convertWithOffsets { startOffset, endOffset ->
enterScope(descriptor) enterScope(descriptor)
val result = irSymbolTable.declareProperty( val result = irSymbolTable.declareProperty(
@@ -936,36 +654,6 @@ class Fir2IrDeclarationStorage(
} }
} }
fun getIrClassSymbol(firClassSymbol: FirClassSymbol<*>): IrClassSymbol {
val firClass = firClassSymbol.fir
getCachedIrClass(firClass)?.let { return irSymbolTable.referenceClass(it.descriptor) }
// TODO: remove all this code and change to unbound symbol creation
val irClass = createIrClass(firClass)
if (firClass is FirAnonymousObject || firClass is FirRegularClass && firClass.visibility == Visibilities.LOCAL) {
return irSymbolTable.referenceClass(irClass.descriptor)
}
val classId = firClassSymbol.classId
val parentId = classId.outerClassId
val irParent = findIrParent(classId.packageFqName, parentId, firClassSymbol)
if (irParent != null) {
irClass.parent = irParent
}
if (irParent is IrExternalPackageFragment) {
addDeclarationsToExternalClass(firClass as FirRegularClass, irClass)
}
return irSymbolTable.referenceClass(irClass.descriptor)
}
fun getIrTypeParameterSymbol(
firTypeParameterSymbol: FirTypeParameterSymbol,
typeContext: ConversionTypeContext
): IrTypeParameterSymbol {
// TODO: use cached type parameter here
val irTypeParameter = getIrTypeParameter(firTypeParameterSymbol.fir, typeContext = typeContext)
return irSymbolTable.referenceTypeParameter(irTypeParameter.descriptor)
}
fun getIrConstructorSymbol(firConstructorSymbol: FirConstructorSymbol): IrConstructorSymbol { fun getIrConstructorSymbol(firConstructorSymbol: FirConstructorSymbol): IrConstructorSymbol {
val firConstructor = firConstructorSymbol.fir val firConstructor = firConstructorSymbol.fir
getCachedIrConstructor(firConstructor)?.let { return irSymbolTable.referenceConstructor(it.descriptor) } getCachedIrConstructor(firConstructor)?.let { return irSymbolTable.referenceConstructor(it.descriptor) }
@@ -1043,11 +731,11 @@ class Fir2IrDeclarationStorage(
fun getIrValueSymbol(firVariableSymbol: FirVariableSymbol<*>): IrSymbol { fun getIrValueSymbol(firVariableSymbol: FirVariableSymbol<*>): IrSymbol {
return when (val firDeclaration = firVariableSymbol.fir) { return when (val firDeclaration = firVariableSymbol.fir) {
is FirEnumEntry -> { is FirEnumEntry -> {
getCachedIrEnumEntry(firDeclaration)?.let { return irSymbolTable.referenceEnumEntry(it.descriptor) } classifierStorage.getCachedIrEnumEntry(firDeclaration)?.let { return irSymbolTable.referenceEnumEntry(it.descriptor) }
val containingFile = firProvider.getFirCallableContainerFile(firVariableSymbol) val containingFile = firProvider.getFirCallableContainerFile(firVariableSymbol)
val parentClassSymbol = firVariableSymbol.callableId.classId?.let { firSymbolProvider.getClassLikeSymbolByFqName(it) } val parentClassSymbol = firVariableSymbol.callableId.classId?.let { firSymbolProvider.getClassLikeSymbolByFqName(it) }
val irParentClass = (parentClassSymbol?.fir as? FirClass<*>)?.let { getCachedIrClass(it) } val irParentClass = (parentClassSymbol?.fir as? FirClass<*>)?.let { classifierStorage.getCachedIrClass(it) }
val irEnumEntry = createIrEnumEntry( val irEnumEntry = classifierStorage.createIrEnumEntry(
firDeclaration, firDeclaration,
irParent = irParentClass, irParent = irParentClass,
origin = if (containingFile == null) IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB else IrDeclarationOrigin.DEFINED origin = if (containingFile == null) IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB else IrDeclarationOrigin.DEFINED
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.types.Variance
class Fir2IrTypeConverter( class Fir2IrTypeConverter(
private val session: FirSession, private val session: FirSession,
private val declarationStorage: Fir2IrDeclarationStorage, private val classifierStorage: Fir2IrClassifierStorage,
private val irBuiltIns: IrBuiltIns private val irBuiltIns: IrBuiltIns
) { ) {
lateinit var nothingType: IrType lateinit var nothingType: IrType
@@ -49,7 +49,7 @@ class Fir2IrTypeConverter(
is ConeLookupTagBasedType -> { is ConeLookupTagBasedType -> {
val irSymbol = getArrayType(this.classId) ?: run { val irSymbol = getArrayType(this.classId) ?: run {
val firSymbol = this.lookupTag.toSymbol(session) ?: return createErrorType() val firSymbol = this.lookupTag.toSymbol(session) ?: return createErrorType()
firSymbol.toIrSymbol(session, declarationStorage, typeContext) firSymbol.toSymbol(session, classifierStorage, typeContext)
} }
// TODO: annotations // TODO: annotations
IrSimpleTypeImpl( IrSimpleTypeImpl(
@@ -47,6 +47,7 @@ import java.util.*
class Fir2IrVisitor( class Fir2IrVisitor(
private val session: FirSession, private val session: FirSession,
private val symbolTable: SymbolTable, private val symbolTable: SymbolTable,
private val classifierStorage: Fir2IrClassifierStorage,
private val declarationStorage: Fir2IrDeclarationStorage, private val declarationStorage: Fir2IrDeclarationStorage,
private val converter: Fir2IrConverter, private val converter: Fir2IrConverter,
private val typeConverter: Fir2IrTypeConverter, private val typeConverter: Fir2IrTypeConverter,
@@ -95,10 +96,10 @@ class Fir2IrVisitor(
// ================================================================================== // ==================================================================================
override fun visitEnumEntry(enumEntry: FirEnumEntry, data: Any?): IrElement { override fun visitEnumEntry(enumEntry: FirEnumEntry, data: Any?): IrElement {
val irEnumEntry = declarationStorage.getCachedIrEnumEntry(enumEntry)!! val irEnumEntry = classifierStorage.getCachedIrEnumEntry(enumEntry)!!
val correspondingClass = irEnumEntry.correspondingClass ?: return irEnumEntry val correspondingClass = irEnumEntry.correspondingClass ?: return irEnumEntry
declarationStorage.enterScope(irEnumEntry.descriptor) declarationStorage.enterScope(irEnumEntry.descriptor)
declarationStorage.putEnumEntryClassInScope(enumEntry, correspondingClass) classifierStorage.putEnumEntryClassInScope(enumEntry, correspondingClass)
converter.processAnonymousObjectMembers(enumEntry.initializer as FirAnonymousObject, correspondingClass) converter.processAnonymousObjectMembers(enumEntry.initializer as FirAnonymousObject, correspondingClass)
conversionScope.withParent(correspondingClass) { conversionScope.withParent(correspondingClass) {
setClassContent(enumEntry.initializer as FirAnonymousObject) setClassContent(enumEntry.initializer as FirAnonymousObject)
@@ -150,7 +151,7 @@ class Fir2IrVisitor(
override fun visitRegularClass(regularClass: FirRegularClass, data: Any?): IrElement { override fun visitRegularClass(regularClass: FirRegularClass, data: Any?): IrElement {
if (regularClass.visibility == Visibilities.LOCAL) { if (regularClass.visibility == Visibilities.LOCAL) {
val irParent = conversionScope.parentFromStack() val irParent = conversionScope.parentFromStack()
val irClass = declarationStorage.getCachedIrClass(regularClass)?.apply { this.parent = irParent } val irClass = classifierStorage.getCachedIrClass(regularClass)?.apply { this.parent = irParent }
if (irClass != null) { if (irClass != null) {
converter.processRegisteredLocalClassAndNestedClasses(regularClass, irClass) converter.processRegisteredLocalClassAndNestedClasses(regularClass, irClass)
return conversionScope.withParent(irClass) { return conversionScope.withParent(irClass) {
@@ -159,7 +160,7 @@ class Fir2IrVisitor(
} }
converter.processLocalClassAndNestedClasses(regularClass, irParent) converter.processLocalClassAndNestedClasses(regularClass, irParent)
} }
val irClass = declarationStorage.getCachedIrClass(regularClass)!! val irClass = classifierStorage.getCachedIrClass(regularClass)!!
return conversionScope.withParent(irClass) { return conversionScope.withParent(irClass) {
setClassContent(regularClass) setClassContent(regularClass)
} }
@@ -168,8 +169,8 @@ class Fir2IrVisitor(
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: Any?): IrElement { override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: Any?): IrElement {
val irParent = conversionScope.parentFromStack() val irParent = conversionScope.parentFromStack()
// NB: for implicit types it is possible that anonymous object is already cached // NB: for implicit types it is possible that anonymous object is already cached
val irAnonymousObject = declarationStorage.getCachedIrClass(anonymousObject)?.apply { this.parent = irParent } val irAnonymousObject = classifierStorage.getCachedIrClass(anonymousObject)?.apply { this.parent = irParent }
?: declarationStorage.createIrAnonymousObject(anonymousObject, irParent = irParent) ?: classifierStorage.createIrAnonymousObject(anonymousObject, irParent = irParent)
converter.processAnonymousObjectMembers(anonymousObject, irAnonymousObject) converter.processAnonymousObjectMembers(anonymousObject, irAnonymousObject)
conversionScope.withParent(irAnonymousObject) { conversionScope.withParent(irAnonymousObject) {
setClassContent(anonymousObject) setClassContent(anonymousObject)
@@ -499,7 +500,7 @@ class Fir2IrVisitor(
private fun FirQualifiedAccess.toIrExpression(typeRef: FirTypeRef): IrExpression { private fun FirQualifiedAccess.toIrExpression(typeRef: FirTypeRef): IrExpression {
val type = typeRef.toIrType() val type = typeRef.toIrType()
val symbol = calleeReference.toSymbol(declarationStorage) val symbol = calleeReference.toSymbol(session, classifierStorage, declarationStorage)
return typeRef.convertWithOffsets { startOffset, endOffset -> return typeRef.convertWithOffsets { startOffset, endOffset ->
if (calleeReference is FirSuperReference) { if (calleeReference is FirSuperReference) {
if (typeRef !is FirComposedSuperTypeRef) { if (typeRef !is FirComposedSuperTypeRef) {
@@ -647,7 +648,7 @@ class Fir2IrVisitor(
it is FirAnonymousObject || it is FirRegularClass && it.classKind == ClassKind.OBJECT it is FirAnonymousObject || it is FirRegularClass && it.classKind == ClassKind.OBJECT
} }
firClass?.convertWithOffsets { startOffset, endOffset -> firClass?.convertWithOffsets { startOffset, endOffset ->
val irClass = declarationStorage.getCachedIrClass(firClass)!! val irClass = classifierStorage.getCachedIrClass(firClass)!!
IrGetObjectValueImpl(startOffset, endOffset, irClass.defaultType, irClass.symbol) IrGetObjectValueImpl(startOffset, endOffset, irClass.defaultType, irClass.symbol)
} }
} }
@@ -715,7 +716,7 @@ class Fir2IrVisitor(
it is FirAnonymousObject || it is FirRegularClass && it.classKind == ClassKind.OBJECT it is FirAnonymousObject || it is FirRegularClass && it.classKind == ClassKind.OBJECT
} }
if (firObject != null) { if (firObject != null) {
val irObject = declarationStorage.getCachedIrClass(firObject)!! val irObject = classifierStorage.getCachedIrClass(firObject)!!
if (irObject != conversionScope.lastClass()) { if (irObject != conversionScope.lastClass()) {
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset -> return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
IrGetObjectValueImpl(startOffset, endOffset, irObject.defaultType, irObject.symbol) IrGetObjectValueImpl(startOffset, endOffset, irObject.defaultType, irObject.symbol)
@@ -750,7 +751,7 @@ class Fir2IrVisitor(
} }
override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, data: Any?): IrElement { override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, data: Any?): IrElement {
val symbol = callableReferenceAccess.calleeReference.toSymbol(declarationStorage) val symbol = callableReferenceAccess.calleeReference.toSymbol(session, classifierStorage, declarationStorage)
val type = callableReferenceAccess.typeRef.toIrType() val type = callableReferenceAccess.typeRef.toIrType()
return callableReferenceAccess.convertWithOffsets { startOffset, endOffset -> return callableReferenceAccess.convertWithOffsets { startOffset, endOffset ->
when (symbol) { when (symbol) {
@@ -792,7 +793,7 @@ class Fir2IrVisitor(
override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: Any?): IrElement { override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: Any?): IrElement {
val calleeReference = variableAssignment.calleeReference val calleeReference = variableAssignment.calleeReference
val symbol = calleeReference.toSymbol(declarationStorage) val symbol = calleeReference.toSymbol(session, classifierStorage, declarationStorage)
return variableAssignment.convertWithOffsets { startOffset, endOffset -> return variableAssignment.convertWithOffsets { startOffset, endOffset ->
if (symbol != null && symbol.isBound) { if (symbol != null && symbol.isBound) {
when (symbol) { when (symbol) {
@@ -1235,7 +1236,7 @@ class Fir2IrVisitor(
val irClassType = argument.typeRef.toIrType() val irClassType = argument.typeRef.toIrType()
val irClassReferenceSymbol = when (argument) { val irClassReferenceSymbol = when (argument) {
is FirResolvedReifiedParameterReference -> { is FirResolvedReifiedParameterReference -> {
declarationStorage.getIrTypeParameterSymbol(argument.symbol, ConversionTypeContext.DEFAULT) classifierStorage.getIrTypeParameterSymbol(argument.symbol, ConversionTypeContext.DEFAULT)
} }
is FirResolvedQualifier -> { is FirResolvedQualifier -> {
val symbol = argument.symbol as? FirClassSymbol val symbol = argument.symbol as? FirClassSymbol
@@ -1244,7 +1245,7 @@ class Fir2IrVisitor(
startOffset, endOffset, irType, "Resolved qualifier ${argument.render()} does not have correct symbol" startOffset, endOffset, irType, "Resolved qualifier ${argument.render()} does not have correct symbol"
) )
} }
declarationStorage.getIrClassSymbol(symbol) classifierStorage.getIrClassSymbol(symbol)
} }
else -> null else -> null
} }
@@ -1274,7 +1275,7 @@ class Fir2IrVisitor(
if (classSymbol != null) { if (classSymbol != null) {
IrGetObjectValueImpl( IrGetObjectValueImpl(
startOffset, endOffset, irType, startOffset, endOffset, irType,
classSymbol.toIrSymbol(session, declarationStorage) as IrClassSymbol classSymbol.toSymbol(session, classifierStorage) as IrClassSymbol
) )
} else { } else {
IrErrorCallExpressionImpl( IrErrorCallExpressionImpl(