[FIR2IR] Don't create IR functions when their symbol is referenced

KT-62856
This commit is contained in:
Dmitriy Novozhilov
2023-11-10 17:59:15 +02:00
committed by Space Team
parent 547d6066a9
commit e3a22791ff
9 changed files with 112 additions and 92 deletions
@@ -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
}
}
}
@@ -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
@@ -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<IrPropertySymbol> {
@@ -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(
@@ -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
}
@@ -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()
}
@@ -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
}
}
}
@@ -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?
@@ -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" }
}
}