[FIR2IR] Get rid of builtin classes scope precaching

Previously it was required to generate fake-overrides for builtin classes
  beforehead, but during fix of KT-60924 it is no longer required

^KT-60924
This commit is contained in:
Dmitriy Novozhilov
2023-09-18 14:11:32 +03:00
committed by Space Team
parent 4e08cafc78
commit e31ee1fa57
4 changed files with 41 additions and 119 deletions
@@ -9,6 +9,7 @@ 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.classId
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass
@@ -26,7 +27,6 @@ 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.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
@@ -66,42 +66,6 @@ class Fir2IrClassifierStorage(
private fun FirTypeRef.toIrType(typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT): IrType =
with(typeConverter) { toIrType(typeOrigin) }
// ------------------------------------ preprocessing ------------------------------------
fun preCacheBuiltinClasses() {
fun getResolvedClass(classId: ClassId): FirRegularClass? {
// toSymbol() can return null when using an old stdlib that's missing some types
val firClass = classId.toSymbol(session)?.fir as FirRegularClass? ?: return null
// Built-in classes may come from sources in the Kotlin project, and so have unresolved types in signatures.
// Still, we need return types for all members to make a list of 'IrDeclarations'. Also see 'Fir2IrLazyClass.declarations'.
firClass.lazyResolveToPhaseWithCallableMembers(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE)
return firClass
}
for ((classId, irBuiltinSymbol) in typeConverter.classIdToSymbolMap) {
val firClass = getResolvedClass(classId) ?: continue
@OptIn(IrSymbolInternals::class)
val irClass = irBuiltinSymbol.owner
classCache[firClass] = irClass
classifiersGenerator.processClassHeader(firClass, irClass)
declarationStorage.preCacheBuiltinClassMembers(firClass, irClass)
}
for ((primitiveClassId, primitiveArrayId) in StandardClassIds.primitiveArrayTypeByElementType) {
// toSymbol() can return null when using an old stdlib that's missing some types
val firClass = getResolvedClass(primitiveArrayId) ?: continue
val irType = typeConverter.classIdToTypeMap[primitiveClassId]
@OptIn(IrSymbolInternals::class)
val irClass = irBuiltIns.primitiveArrayForType[irType]!!.owner
classCache[firClass] = irClass
classifiersGenerator.processClassHeader(firClass, irClass)
declarationStorage.preCacheBuiltinClassMembers(firClass, irClass)
}
}
// ------------------------------------ type parameters ------------------------------------
// Note: declareTypeParameters should be called before!
@@ -197,11 +161,17 @@ class Fir2IrClassifierStorage(
predefinedOrigin: IrDeclarationOrigin? = null
): IrClass {
return classifiersGenerator.createIrClass(regularClass, parent, predefinedOrigin).also {
if (regularClass.visibility == Visibilities.Local) {
localStorage[regularClass] = it
} else {
classCache[regularClass] = it
}
@OptIn(LeakedDeclarationCaches::class)
cacheIrClass(regularClass, it)
}
}
@LeakedDeclarationCaches
internal fun cacheIrClass(regularClass: FirRegularClass, irClass: IrClass) {
if (regularClass.visibility == Visibilities.Local) {
localStorage[regularClass] = irClass
} else {
classCache[regularClass] = irClass
}
}
@@ -65,15 +65,11 @@ class Fir2IrConverter(
private fun runSourcesConversion(
allFirFiles: List<FirFile>,
irModuleFragment: IrModuleFragmentImpl,
fir2irVisitor: Fir2IrVisitor,
runPreCacheBuiltinClasses: Boolean
fir2irVisitor: Fir2IrVisitor
) {
for (firFile in allFirFiles) {
registerFileAndClasses(firFile, irModuleFragment)
}
if (runPreCacheBuiltinClasses) {
classifierStorage.preCacheBuiltinClasses()
}
// The file processing is performed phase-to-phase:
// 1. Creation of all non-local regular classes
// 2. Class header processing (type parameters, supertypes, this receiver)
@@ -573,7 +569,9 @@ class Fir2IrConverter(
}
components.converter.runSourcesConversion(
allFirFiles, irModuleFragment, components.fir2IrVisitor, runPreCacheBuiltinClasses = initializedIrBuiltIns == null
allFirFiles,
irModuleFragment,
components.fir2IrVisitor
)
if (fir2IrConfiguration.useIrFakeOverrideBuilder) {
@@ -152,46 +152,6 @@ class Fir2IrDeclarationStorage(
private val localStorage: Fir2IrLocalCallableStorage by threadLocal { Fir2IrLocalCallableStorage() }
// ------------------------------------ preprocessing ------------------------------------
internal fun preCacheBuiltinClassMembers(firClass: FirRegularClass, irClass: IrClass) {
for (declaration in firClass.declarations) {
when (declaration) {
is FirProperty -> {
val irProperty = irClass.properties.find { it.name == declaration.name }
if (irProperty != null) {
propertyCache[declaration] = irProperty
}
}
is FirSimpleFunction -> {
val irFunction = irClass.functions.find {
areCompatible(declaration, it)
}
if (irFunction != null) {
functionCache[declaration] = irFunction
}
}
is FirConstructor -> {
val irConstructor = irClass.constructors.find {
areCompatible(declaration, it)
}
if (irConstructor != null) {
constructorCache[declaration] = irConstructor
}
}
else -> {}
}
}
val scope = firClass.unsubstitutedScope()
scope.getCallableNames().forEach { callableName ->
buildList {
fakeOverrideGenerator.generateFakeOverridesForName(
irClass, scope, callableName, firClass, this, realDeclarationSymbols = emptySet()
)
}.also(fakeOverrideGenerator::bindOverriddenSymbols)
}
}
// ------------------------------------ package fragments ------------------------------------
fun getIrExternalPackageFragment(
@@ -1278,34 +1238,6 @@ class Fir2IrDeclarationStorage(
)
}
private fun areCompatible(firFunction: FirFunction, irFunction: IrFunction): Boolean {
if (firFunction is FirSimpleFunction && irFunction is IrSimpleFunction) {
if (irFunction.name != firFunction.name) return false
}
return irFunction.valueParameters.size == firFunction.valueParameters.size &&
irFunction.valueParameters.zip(firFunction.valueParameters).all { (irParameter, firParameter) ->
val irType = irParameter.type
val firType = firParameter.returnTypeRef.coneType
if (irType is IrSimpleType) {
when (val irClassifierSymbol = irType.classifier) {
is IrTypeParameterSymbol -> {
firType is ConeTypeParameterType
}
is IrClassSymbol -> {
@OptIn(IrSymbolInternals::class)
val irClass = irClassifierSymbol.owner
firType is ConeClassLikeType && irClass.name == firType.lookupTag.name
}
is IrScriptSymbol -> {
false
}
}
} else {
false
}
}
}
private inline fun <reified S : IrSymbol, reified D : IrOverridableDeclaration<S>> ConeClassLookupTagWithFixedSymbol.findIrFakeOverride(
name: Name, originalDeclaration: IrOverridableDeclaration<S>
): IrSymbol? {
@@ -129,9 +129,31 @@ class IrBuiltInsOverFir(
override val stringType: IrType get() = stringClass.defaultTypeWithoutArguments
internal val intrinsicConst by lazy {
// Old versions of stdlib may not contain @IntrinsicConstEvaluation (AV < 1.7),
// so in this case we should create annotation class manually
/*loadClassSafe(StandardClassIds.Annotations.IntrinsicConstEvaluation) ?: */createIntrinsicConstEvaluationClass().symbol
/*
* Old versions of stdlib may not contain @IntrinsicConstEvaluation (AV < 1.7), so in this case we should create annotation class manually
*
* Ideally, we should try to load it from FIR at first, but the thing is that this annotation is used for some generated builtin functions
* (see init section below), so if Fir2IrLazyClass for this annotation is created, it will call for `components.fakeOverrideGenerator`,
* which is not initialized by this moment
* As a possible way to fix it we can move `init` section of builtins into the separate function for late initialization and call
* for it after Fir2IrComponentsStorage is fully initialized
*/
val irClass = createIntrinsicConstEvaluationClass()
val firClassSymbol = session.symbolProvider.getClassLikeSymbolByClassId(
StandardClassIds.Annotations.IntrinsicConstEvaluation
) as FirRegularClassSymbol?
if (firClassSymbol != null) {
/*
* If @IntrinsicConstEvaluation is present in dependencies, we should manually cache relation between FIR and IR class
* Without it classifier storage may create another IR class for @IntrinsicConstEvaluation, if it will be referenced
* somewhere in the code
*/
@OptIn(LeakedDeclarationCaches::class)
components.classifierStorage.cacheIrClass(firClassSymbol.fir, irClass)
}
irClass.symbol
}
private val intrinsicConstAnnotation: IrConstructorCall by lazy {