From 6c5557dae3a1b5f096fc9dc15c2f2ca12962572b Mon Sep 17 00:00:00 2001 From: "Denis.Zharkov" Date: Thu, 25 Feb 2021 17:48:21 +0300 Subject: [PATCH] FIR2IR: Optimize computation of fake overrides in lazy classes --- .../fir/backend/Fir2IrDeclarationStorage.kt | 5 +- .../generators/FakeOverrideGenerator.kt | 133 +++++++++++------- .../kotlin/fir/lazy/Fir2IrLazyClass.kt | 15 +- 3 files changed, 97 insertions(+), 56 deletions(-) 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 5538d589258..2eb5e96a600 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 @@ -866,8 +866,9 @@ class Fir2IrDeclarationStorage( irClass: IrClass, callableDeclaration: FirCallableDeclaration<*> ): FirCallableDeclaration<*>? { - // Init lazy class if necessary - irClass.declarations + if (irClass is Fir2IrLazyClass) { + irClass.getFakeOverridesByName(callableDeclaration.symbol.callableId.callableName) + } return fakeOverridesInClass[irClass]?.get(callableDeclaration) } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt index 3b6fe8e370d..ed09bd55d37 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities +import org.jetbrains.kotlin.name.Name class FakeOverrideGenerator( private val components: Fir2IrComponents, @@ -70,60 +71,86 @@ class FakeOverrideGenerator( val useSiteMemberScope = klass.unsubstitutedScope(session, scopeSession, withForcedTypeCalculator = true) val superTypesCallableNames = useSiteMemberScope.getCallableNames() val realDeclarationSymbols = realDeclarations.filterIsInstance>().mapTo(mutableSetOf(), FirSymbolOwner<*>::symbol) - val isLocal = klass !is FirRegularClass || klass.isLocal - for (name in superTypesCallableNames) { - useSiteMemberScope.processFunctionsByName(name) { functionSymbol -> - createFakeOverriddenIfNeeded( - klass, this, isLocal, functionSymbol, - declarationStorage::getCachedIrFunction, - declarationStorage::createIrFunction, - createFakeOverrideSymbol = { firFunction, callableSymbol -> - FirFakeOverrideGenerator.createSubstitutionOverrideFunction( - session, firFunction, callableSymbol, - newDispatchReceiverType = klass.defaultType(), - derivedClassId = klass.symbol.classId, - isExpect = (klass as? FirRegularClass)?.isExpect == true - ) - }, - baseFunctionSymbols, - result, - containsErrorTypes = { irFunction -> - irFunction.returnType.containsErrorType() || irFunction.valueParameters.any { it.type.containsErrorType() } - }, - realDeclarationSymbols, - FirTypeScope::getDirectOverriddenFunctions, - useSiteMemberScope, - ) - } - useSiteMemberScope.processPropertiesByName(name) { propertySymbol -> - createFakeOverriddenIfNeeded( - klass, this, isLocal, propertySymbol, - declarationStorage::getCachedIrProperty, - declarationStorage::createIrProperty, - createFakeOverrideSymbol = { firProperty, callableSymbol -> - FirFakeOverrideGenerator.createSubstitutionOverrideProperty( - session, firProperty, callableSymbol, - newDispatchReceiverType = klass.defaultType(), - derivedClassId = klass.symbol.classId, - isExpect = (klass as? FirRegularClass)?.isExpect == true - ) - }, - basePropertySymbols, - result, - containsErrorTypes = { irProperty -> - irProperty.backingField?.type?.containsErrorType() == true || - irProperty.getter?.returnType?.containsErrorType() == true - }, - realDeclarationSymbols, - FirTypeScope::getDirectOverriddenProperties, - useSiteMemberScope, - ) - } + for (name in superTypesCallableNames) { + generateFakeOverridesForName(this, useSiteMemberScope, name, klass, result, realDeclarationSymbols) } return result } + @OptIn(ExperimentalStdlibApi::class) + fun generateFakeOverridesForName( + irClass: IrClass, + name: Name, + firClass: FirClass<*> + ): List = buildList { + val useSiteMemberScope = firClass.unsubstitutedScope(session, scopeSession, withForcedTypeCalculator = true) + generateFakeOverridesForName( + irClass, useSiteMemberScope, name, firClass, this, + // This parameter is only needed for data-class methods that is irrelevant for lazy library classes + realDeclarationSymbols = emptySet() + ) + } + + private fun generateFakeOverridesForName( + irClass: IrClass, + useSiteMemberScope: FirTypeScope, + name: Name, + firClass: FirClass<*>, + result: MutableList, + realDeclarationSymbols: Set> + ) { + val isLocal = firClass !is FirRegularClass || firClass.isLocal + useSiteMemberScope.processFunctionsByName(name) { functionSymbol -> + createFakeOverriddenIfNeeded( + firClass, irClass, isLocal, functionSymbol, + declarationStorage::getCachedIrFunction, + declarationStorage::createIrFunction, + createFakeOverrideSymbol = { firFunction, callableSymbol -> + FirFakeOverrideGenerator.createSubstitutionOverrideFunction( + session, firFunction, callableSymbol, + newDispatchReceiverType = firClass.defaultType(), + derivedClassId = firClass.symbol.classId, + isExpect = (firClass as? FirRegularClass)?.isExpect == true + ) + }, + baseFunctionSymbols, + result, + containsErrorTypes = { irFunction -> + irFunction.returnType.containsErrorType() || irFunction.valueParameters.any { it.type.containsErrorType() } + }, + realDeclarationSymbols, + FirTypeScope::getDirectOverriddenFunctions, + useSiteMemberScope, + ) + } + + useSiteMemberScope.processPropertiesByName(name) { propertySymbol -> + createFakeOverriddenIfNeeded( + firClass, irClass, isLocal, propertySymbol, + declarationStorage::getCachedIrProperty, + declarationStorage::createIrProperty, + createFakeOverrideSymbol = { firProperty, callableSymbol -> + FirFakeOverrideGenerator.createSubstitutionOverrideProperty( + session, firProperty, callableSymbol, + newDispatchReceiverType = firClass.defaultType(), + derivedClassId = firClass.symbol.classId, + isExpect = (firClass as? FirRegularClass)?.isExpect == true + ) + }, + basePropertySymbols, + result, + containsErrorTypes = { irProperty -> + irProperty.backingField?.type?.containsErrorType() == true || + irProperty.getter?.returnType?.containsErrorType() == true + }, + realDeclarationSymbols, + FirTypeScope::getDirectOverriddenProperties, + useSiteMemberScope, + ) + } + } + internal fun calcBaseSymbolsForFakeOverrideFunction( klass: FirClass<*>, fakeOverride: IrSimpleFunction, @@ -158,10 +185,16 @@ class FakeOverrideGenerator( computeDirectOverridden: FirTypeScope.(S) -> List, scope: FirTypeScope, ) { - if (originalSymbol !is S || originalSymbol in realDeclarationSymbols) return + if (originalSymbol !is S) return val classLookupTag = klass.symbol.toLookupTag() val originalDeclaration = originalSymbol.fir + if (originalSymbol.dispatchReceiverClassOrNull() == classLookupTag && !originalDeclaration.origin.fromSupertypes) return + // Data classes' methods from Any (toString/equals/hashCode) are not handled by the line above because they have Any-typed dispatch receiver + // (there are no special FIR method for them, it's just fake overrides) + // But they are treated differently in IR (real declarations have already been declared before) and such methods are present among realDeclarationSymbols + if (originalSymbol in realDeclarationSymbols) return + if (originalDeclaration.visibility == Visibilities.Private) return val origin = IrDeclarationOrigin.FAKE_OVERRIDE diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt index 8e88c2b00f1..8e8a49b226e 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt @@ -117,6 +117,13 @@ class Fir2IrLazyClass( receiver } + private val fakeOverridesByName = mutableMapOf>() + + fun getFakeOverridesByName(name: Name): Collection = fakeOverridesByName.getOrPut(name) { + fakeOverrideGenerator.generateFakeOverridesForName(this@Fir2IrLazyClass, name, fir) + .also(fakeOverrideGenerator::bindOverriddenSymbols) + } + override val declarations: MutableList by lazyVar { val result = mutableListOf() val processedNames = mutableSetOf() @@ -166,11 +173,11 @@ class Fir2IrLazyClass( else -> continue } } - with(fakeOverrideGenerator) { - val fakeOverrides = getFakeOverrides(fir, fir.declarations) - bindOverriddenSymbols(fakeOverrides) - result += fakeOverrides + + for (name in scope.getCallableNames()) { + result += getFakeOverridesByName(name) } + // TODO: remove this check to save time for (declaration in result) { if (declaration.parent != this) {