From e31ee1fa57a00a71b3e4500c34a0bd5ed821b54e Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Mon, 18 Sep 2023 14:11:32 +0300 Subject: [PATCH] [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 --- .../fir/backend/Fir2IrClassifierStorage.kt | 54 ++++----------- .../kotlin/fir/backend/Fir2IrConverter.kt | 10 ++- .../fir/backend/Fir2IrDeclarationStorage.kt | 68 ------------------- .../kotlin/fir/backend/IrBuiltInsOverFir.kt | 28 +++++++- 4 files changed, 41 insertions(+), 119 deletions(-) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt index 857d4a919a0..c45d39b67ee 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt @@ -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 } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt index 08d4d92e4c8..199e09cf395 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt @@ -65,15 +65,11 @@ class Fir2IrConverter( private fun runSourcesConversion( allFirFiles: List, 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) { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt index 418a2615342..3451c5e0c07 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt @@ -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 > ConeClassLookupTagWithFixedSymbol.findIrFakeOverride( name: Name, originalDeclaration: IrOverridableDeclaration ): IrSymbol? { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt index a7e7b519ef4..37363dca416 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt @@ -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 {