[FIR2IR] Don't create IR functions when their symbol is referenced
KT-62856
This commit is contained in:
committed by
Space Team
parent
547d6066a9
commit
e3a22791ff
+59
-60
@@ -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> {
|
||||
|
||||
+9
-1
@@ -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(
|
||||
|
||||
+19
-13
@@ -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
|
||||
}
|
||||
|
||||
+5
-5
@@ -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" }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user