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 e2f71683a9d..2af3af269e3 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 @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.builtins.StandardNames.BUILT_INS_PACKAGE_FQ_NAMES import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.fir.* +import org.jetbrains.kotlin.fir.backend.generators.isExternalParent import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.builder.buildProperty import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty @@ -19,8 +20,10 @@ import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.java.symbols.FirJavaOverriddenSyntheticPropertySymbol import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass +import org.jetbrains.kotlin.fir.lazy.Fir2IrLazySimpleFunction import org.jetbrains.kotlin.fir.references.toResolvedValueParameterSymbol import org.jetbrains.kotlin.fir.resolve.providers.firProvider +import org.jetbrains.kotlin.fir.resolve.toFirRegularClass import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol @@ -264,64 +267,27 @@ class Fir2IrDeclarationStorage( return cachedIrCallable } - @GetOrCreateSensitiveAPI - fun getOrCreateIrFunction( - function: FirFunction, - irParent: IrDeclarationParent?, - predefinedOrigin: IrDeclarationOrigin? = null, - isLocal: Boolean = false, - fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null - ): IrSimpleFunction { - return getOrCreateIrFunction(function, { irParent }, predefinedOrigin, isLocal, fakeOverrideOwnerLookupTag) - } - - @GetOrCreateSensitiveAPI - private fun getOrCreateIrFunction( - function: FirFunction, - irParent: () -> IrDeclarationParent?, - predefinedOrigin: IrDeclarationOrigin? = null, - isLocal: Boolean = false, - fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null - ): IrSimpleFunction { - @OptIn(UnsafeDuringIrConstructionAPI::class) - getCachedIrFunctionSymbol(function, fakeOverrideOwnerLookupTag)?.ownerIfBound()?.let { return it } - /* - * Declaration storage doesn't know how to create lazy fake-overrides, it is responsibility of - * FakeOverrideGenerator. So if function to be created is potentially lazy fake-override, we - * need to call FakeOverrideGenerator before checking any caches. Otherwise it will lead to - * the situation when lazy fake override is created based on original FIR function, not - * its f/o copy (which causes troubles with type parameters mapping) - */ - if (fakeOverrideOwnerLookupTag != function.containingClassLookupTag()) { - generateLazyFakeOverrides(function.nameOrSpecialName, fakeOverrideOwnerLookupTag) - @OptIn(UnsafeDuringIrConstructionAPI::class) - getCachedIrFunctionSymbol(function, fakeOverrideOwnerLookupTag)?.ownerIfBound()?.let { return it } - } - return createAndCacheIrFunction(function, irParent(), predefinedOrigin, isLocal, fakeOverrideOwnerLookupTag) - } - + /** + * @param allowLazyDeclarationsCreation should be passed only during fake-override generation + */ fun createAndCacheIrFunction( function: FirFunction, irParent: IrDeclarationParent?, predefinedOrigin: IrDeclarationOrigin? = null, isLocal: Boolean = false, - fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null + fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null, + allowLazyDeclarationsCreation: Boolean = false ): IrSimpleFunction { - val signature = runIf(!isLocal && configuration.linkViaSignatures) { - signatureComposer.composeSignature(function, fakeOverrideOwnerLookupTag) - } - - val irFunction = callablesGenerator.createIrFunction( + val symbol = getIrFunctionSymbol(function.symbol, fakeOverrideOwnerLookupTag, isLocal) as IrSimpleFunctionSymbol + return callablesGenerator.createIrFunction( function, irParent, - createFunctionSymbol(signature), + symbol, predefinedOrigin, isLocal = isLocal, - fakeOverrideOwnerLookupTag = fakeOverrideOwnerLookupTag + fakeOverrideOwnerLookupTag = fakeOverrideOwnerLookupTag, + allowLazyDeclarationsCreation ) - cacheIrFunction(function, irFunction, fakeOverrideOwnerLookupTag) - - return irFunction } internal fun createFunctionSymbol(signature: IdSignature?): IrSimpleFunctionSymbol { @@ -331,10 +297,14 @@ class Fir2IrDeclarationStorage( } } - private fun cacheIrFunction(function: FirFunction, irFunction: IrSimpleFunction, fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?) { + private fun cacheIrFunctionSymbol( + function: FirFunction, + irFunctionSymbol: IrSimpleFunctionSymbol, + fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?, + ) { when { - irFunction.visibility == DescriptorVisibilities.LOCAL -> { - localStorage.putLocalFunction(function, irFunction.symbol) + function.visibility == Visibilities.Local || function is FirAnonymousFunction -> { + localStorage.putLocalFunction(function, irFunctionSymbol) } function.isFakeOverrideOrDelegated(fakeOverrideOwnerLookupTag) -> { @@ -343,11 +313,11 @@ class Fir2IrDeclarationStorage( originalFunction.symbol, fakeOverrideOwnerLookupTag ?: function.containingClassLookupTag()!! ) - irForFirSessionDependantDeclarationMap[key] = irFunction.symbol + irForFirSessionDependantDeclarationMap[key] = irFunctionSymbol } else -> { - functionCache[function] = irFunction.symbol + functionCache[function] = irFunctionSymbol } } } @@ -973,21 +943,50 @@ class Fir2IrDeclarationStorage( return map?.get(callableDeclaration.asFakeOverrideKey()) } + private fun FirCallableDeclaration.computeExternalOrigin(): IrDeclarationOrigin { + val containingClass = containingClassLookupTag()?.toFirRegularClass(session) + return when (containingClass?.isJavaOrEnhancement) { + true -> IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB + else -> IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB + } + } + fun getIrFunctionSymbol( firFunctionSymbol: FirFunctionSymbol<*>, fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null, + isLocal: Boolean = false ): IrFunctionSymbol { - return when (val fir = firFunctionSymbol.fir) { + return when (val function = firFunctionSymbol.fir) { is FirConstructor -> { - getIrConstructorSymbol(fir.symbol) + getIrConstructorSymbol(function.symbol) } else -> { - @OptIn(GetOrCreateSensitiveAPI::class) - getOrCreateIrFunction( - fir, - { findIrParent(fir, fakeOverrideOwnerLookupTag) }, - fakeOverrideOwnerLookupTag = fakeOverrideOwnerLookupTag - ).symbol + getCachedIrFunctionSymbol(function, fakeOverrideOwnerLookupTag)?.let { return it } + val signature = runIf(!isLocal && configuration.linkViaSignatures) { + signatureComposer.composeSignature(firFunctionSymbol.fir, fakeOverrideOwnerLookupTag) + } + val symbol = createFunctionSymbol(signature) + if (function is FirSimpleFunction && !isLocal) { + val irParent = findIrParent(function, fakeOverrideOwnerLookupTag) + if (irParent?.isExternalParent() == true) { + // Return value is not used here, because creation of IR declaration binds it to the corresponding symbol + // And all we want here is to bind symbol for lazy declaration + callablesGenerator.createIrFunction( + function, + irParent, + symbol, + predefinedOrigin = function.computeExternalOrigin(), + isLocal = false, + fakeOverrideOwnerLookupTag, + allowLazyDeclarationsCreation = true + ).also { + check(it is Fir2IrLazySimpleFunction) + } + } + } + + cacheIrFunctionSymbol(function, symbol, fakeOverrideOwnerLookupTag) + return symbol } } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/FirIrProvider.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/FirIrProvider.kt index 99973e87a11..898aa78ac12 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/FirIrProvider.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/FirIrProvider.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled class FirIrProvider(val components: Fir2IrComponents) : IrProvider { private val symbolProvider = components.session.symbolProvider @@ -173,8 +174,7 @@ class FirIrProvider(val components: Fir2IrComponents) : IrProvider { declarationStorage.getOrCreateIrConstructor(firConstructor, parent as IrClass) } SymbolKind.FUNCTION_SYMBOL -> { - val firSimpleFunction = firDeclaration as FirSimpleFunction - declarationStorage.getOrCreateIrFunction(firSimpleFunction, parent) + shouldNotBeCalled() } SymbolKind.PROPERTY_SYMBOL -> { val firProperty = firDeclaration as FirProperty 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 3f73b95441a..683f0887eb0 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 @@ -696,10 +696,7 @@ class IrBuiltInsOverFir( private fun findFunction(functionSymbol: FirNamedFunctionSymbol): IrSimpleFunctionSymbol { functionSymbol.lazyResolveToPhase(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) - - val irParent = findIrParent(functionSymbol) - @OptIn(GetOrCreateSensitiveAPI::class) - return components.declarationStorage.getOrCreateIrFunction(functionSymbol.fir, irParent).symbol + return components.declarationStorage.getIrFunctionSymbol(functionSymbol) as IrSimpleFunctionSymbol } private fun findProperties(packageName: FqName, name: Name): List { 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 884fb270d07..1c92a63fea0 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 @@ -96,7 +96,15 @@ class FakeOverrideGenerator( createFakeOverriddenIfNeeded( firClass, irClass, isLocal, functionSymbol, declarationStorage::getCachedIrFunctionSymbol, - declarationStorage::createAndCacheIrFunction, + { function, irParent, predefinedOrigin, isLocal -> + declarationStorage.createAndCacheIrFunction( + function, + irParent, + predefinedOrigin, + isLocal, + allowLazyDeclarationsCreation = true + ) + }, createFakeOverrideSymbol = { firFunction, callableSymbol -> val symbol = FirFakeOverrideGenerator.createSymbolForSubstitutionOverride(callableSymbol, firClass.symbol.classId) FirFakeOverrideGenerator.createSubstitutionOverrideFunction( diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrCallableDeclarationsGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrCallableDeclarationsGenerator.kt index 0cb068193c2..25b4b55845e 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrCallableDeclarationsGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrCallableDeclarationsGenerator.kt @@ -74,9 +74,10 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi function: FirFunction, irParent: IrDeclarationParent?, symbol: IrSimpleFunctionSymbol, - predefinedOrigin: IrDeclarationOrigin? = null, - isLocal: Boolean = false, - fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null, + predefinedOrigin: IrDeclarationOrigin?, + isLocal: Boolean, + fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?, + allowLazyDeclarationsCreation: Boolean ): IrSimpleFunction = convertCatching(function) { val simpleFunction = function as? FirSimpleFunction val isLambda = function is FirAnonymousFunction && function.isLambda @@ -100,8 +101,13 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi ) } if (irParent.isExternalParent()) { - // For private functions signature is null, fallback to non-lazy function - return lazyDeclarationsGenerator.createIrLazyFunction(function as FirSimpleFunction, symbol, irParent!!, updatedOrigin) + require(function is FirSimpleFunction) + if (!allowLazyDeclarationsCreation) { + error("Lazy functions should be processed in Fir2IrDeclarationStorage") + } + @OptIn(UnsafeDuringIrConstructionAPI::class) + if (symbol.isBound) return symbol.owner + return lazyDeclarationsGenerator.createIrLazyFunction(function, symbol, irParent, updatedOrigin) } val name = simpleFunction?.name ?: if (isLambda) SpecialNames.ANONYMOUS else SpecialNames.NO_NAME_PROVIDED @@ -362,14 +368,6 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi } } - @OptIn(ExperimentalContracts::class) - private fun IrDeclarationParent?.isExternalParent(): Boolean { - contract { - returns(true) implies (this@isExternalParent != null) - } - return this is Fir2IrLazyClass || this is IrExternalPackageFragment - } - /** * In partial module compilation (see [org.jetbrains.kotlin.analysis.api.fir.components.KtFirCompilerFacility]), * referenced properties might be resolved only up to [FirResolvePhase.CONTRACTS], @@ -1045,3 +1043,11 @@ internal fun addDeclarationToParent(declaration: IrDeclaration, irParent: IrDecl else -> error("Can't add declaration ${declaration.render()} to parent ${irParent.render()}") } } + +@OptIn(ExperimentalContracts::class) +internal fun IrDeclarationParent?.isExternalParent(): Boolean { + contract { + returns(true) implies (this@isExternalParent != null) + } + return this is Fir2IrLazyClass || this is IrExternalPackageFragment +} diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyDeclarationsGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyDeclarationsGenerator.kt index 16a2f7c9e82..b33b2b125d9 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyDeclarationsGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyDeclarationsGenerator.kt @@ -39,11 +39,6 @@ class Fir2IrLazyDeclarationsGenerator(val components: Fir2IrComponents) : Fir2Ir return irFunction } - private fun FirCallableDeclaration.isFakeOverride(firContainingClass: FirRegularClass?): Boolean { - val declaration = unwrapUseSiteSubstitutionOverrides() - return declaration.isSubstitutionOrIntersectionOverride || firContainingClass?.symbol?.toLookupTag() != declaration.containingClassLookupTag() - } - internal fun createIrLazyProperty( fir: FirProperty, lazyParent: IrDeclarationParent, @@ -101,3 +96,8 @@ class Fir2IrLazyDeclarationsGenerator(val components: Fir2IrComponents) : Fir2Ir } } } + +internal fun FirCallableDeclaration.isFakeOverride(firContainingClass: FirRegularClass?): Boolean { + val declaration = unwrapUseSiteSubstitutionOverrides() + return declaration.isSubstitutionOrIntersectionOverride || firContainingClass?.symbol?.toLookupTag() != declaration.containingClassLookupTag() +} 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 d293c3f6034..27b1f954f49 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 @@ -160,6 +160,7 @@ class Fir2IrLazyClass( // NB: it's necessary to take all callables from scope, // e.g. to avoid accessing un-enhanced Java declarations with FirJavaTypeRef etc. inside val scope = fir.unsubstitutedScope() + val lookupTag = fir.symbol.toLookupTag() scope.processDeclaredConstructors { val constructor = it.fir if (shouldBuildStub(constructor)) { @@ -197,8 +198,9 @@ class Fir2IrLazyClass( symbol.containingClassLookupTag() != ownerLookupTag -> {} symbol.isAbstractMethodOfAny() -> {} else -> { - @OptIn(GetOrCreateSensitiveAPI::class) - result += declarationStorage.getOrCreateIrFunction(symbol.fir, this, origin) + // Lazy declarations are created together with their symbol, so it's safe to take the owner here + @OptIn(UnsafeDuringIrConstructionAPI::class) + result += declarationStorage.getIrFunctionSymbol(symbol, lookupTag).owner } } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyPropertyAccessor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyPropertyAccessor.kt index 046121f5973..bda10c78b7d 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyPropertyAccessor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyPropertyAccessor.kt @@ -125,8 +125,13 @@ class Fir2IrLazyPropertyAccessor( override val initialSignatureFunction: IrFunction? by lazy { val originalFirFunction = (fir as? FirSyntheticPropertyAccessor)?.delegate ?: return@lazy null - @OptIn(GetOrCreateSensitiveAPI::class) - declarationStorage.getOrCreateIrFunction(originalFirFunction, parent) + // If property accessor is created then corresponding property is definitely created too + @OptIn(UnsafeDuringIrConstructionAPI::class) + val lookupTag = (correspondingPropertySymbol!!.owner as Fir2IrLazyProperty).containingClass?.symbol?.toLookupTag() + + // `initialSignatureFunction` is not called during fir2ir conversion + @OptIn(UnsafeDuringIrConstructionAPI::class) + declarationStorage.getIrFunctionSymbol(originalFirFunction.symbol, lookupTag).owner } override val containerSource: DeserializedContainerSource? diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt index a87555a93b7..c2b9fab9be0 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.fir.lazy import org.jetbrains.kotlin.fir.backend.Fir2IrComponents -import org.jetbrains.kotlin.fir.backend.GetOrCreateSensitiveAPI import org.jetbrains.kotlin.fir.backend.contextReceiversForFunctionOrContainingProperty import org.jetbrains.kotlin.fir.backend.generators.Fir2IrCallableDeclarationsGenerator import org.jetbrains.kotlin.fir.backend.generators.generateOverriddenFunctionSymbols @@ -22,6 +21,7 @@ import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.declarations.lazy.lazyVar import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.UnsafeDuringIrConstructionAPI import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource @@ -111,8 +111,11 @@ class Fir2IrLazySimpleFunction( override val initialSignatureFunction: IrFunction? by lazy { val originalFunction = fir.initialSignatureAttr as? FirFunction ?: return@lazy null - @OptIn(GetOrCreateSensitiveAPI::class) - declarationStorage.getOrCreateIrFunction(originalFunction, parent).also { + val lookupTag = firParent?.symbol?.toLookupTag() + + // `initialSignatureFunction` is not called during fir2ir conversion + @OptIn(UnsafeDuringIrConstructionAPI::class) + declarationStorage.getIrFunctionSymbol(originalFunction.symbol, lookupTag).owner.also { check(it !== this) { "Initial function can not be the same as remapped function" } } }