[FIR2IR] Simplify Fir2IrDeclarationStorage.getIrPropertySymbol

For reasoning refer to the message of the previous commit
It is the same as for `getIrFunctionSymbol`

There is one failing test here, caused by KT-61941
The issue was here before this commit, but it was hidden
This commit is contained in:
Dmitriy Novozhilov
2023-09-14 16:21:44 +03:00
committed by Space Team
parent 1e090d45d1
commit 50425e82c5
8 changed files with 101 additions and 150 deletions
@@ -448,11 +448,26 @@ class Fir2IrDeclarationStorage(
predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null
): IrProperty {
return getOrCreateIrProperty(property, { irParent }, predefinedOrigin, isLocal, fakeOverrideOwnerLookupTag)
}
fun getOrCreateIrProperty(
property: FirProperty,
irParent: () -> IrDeclarationParent?,
predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null
): IrProperty {
@Suppress("NAME_SHADOWING")
val property = prepareProperty(property)
getCachedIrProperty(property)?.let { return it }
return createAndCacheIrProperty(property, irParent, predefinedOrigin, isLocal, fakeOverrideOwnerLookupTag)
getCachedIrProperty(property, fakeOverrideOwnerLookupTag)?.let { return it }
// See comment in [getOrCreateIrFunction]
if (fakeOverrideOwnerLookupTag != property.containingClassLookupTag()) {
generateLazyFakeOverrides(property.name, fakeOverrideOwnerLookupTag)
getCachedIrProperty(property, fakeOverrideOwnerLookupTag)?.let { return it }
}
return createAndCacheIrProperty(property, irParent(), predefinedOrigin, isLocal, fakeOverrideOwnerLookupTag)
}
fun getOrCreateIrPropertyByPureField(
@@ -535,71 +550,22 @@ class Fir2IrDeclarationStorage(
firPropertySymbol: FirPropertySymbol,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null,
): IrSymbol {
@Suppress("NAME_SHADOWING")
val firPropertySymbol = preparePropertySymbol(firPropertySymbol)
val fir = firPropertySymbol.fir
if (fir.isLocal) {
return localStorage.getDelegatedProperty(fir)?.symbol ?: getIrVariableSymbol(fir)
val firProperty = prepareProperty(firPropertySymbol.fir)
if (firProperty.isLocal) {
return localStorage.getDelegatedProperty(firProperty)?.symbol ?: getIrVariableSymbol(firProperty)
}
val containingClassLookupTag = firPropertySymbol.containingClassLookupTag()
val unmatchedOwner = fakeOverrideOwnerLookupTag != containingClassLookupTag
if (unmatchedOwner) {
generateLazyFakeOverrides(fir.name, fakeOverrideOwnerLookupTag)
}
fun ConeClassLikeLookupTag?.getIrCallableSymbol() = getIrCallableSymbol(
firPropertySymbol,
fakeOverrideOwnerLookupTag = this,
getCachedIrDeclaration = ::getCachedIrProperty,
createIrDeclaration = { parent, origin ->
createAndCacheIrProperty(
fir, parent, predefinedOrigin = origin, fakeOverrideOwnerLookupTag = fakeOverrideOwnerLookupTag,
)
},
createIrLazyDeclaration = { signature, lazyParent, declarationOrigin ->
lazyDeclarationsGenerator.createIrLazyProperty(fir, signature, lazyParent, declarationOrigin).also {
cacheIrProperty(fir, it, fakeOverrideOwnerLookupTag = null)
}
},
val result = getOrCreateIrProperty(
firProperty,
{ findIrParent(firProperty, fakeOverrideOwnerLookupTag) },
fakeOverrideOwnerLookupTag = fakeOverrideOwnerLookupTag
)
val originalSymbol = fakeOverrideOwnerLookupTag.getIrCallableSymbol()
@OptIn(IrSymbolInternals::class)
val originalProperty = originalSymbol.owner as IrProperty
fun IrProperty.isIllegalFakeOverride(): Boolean {
if (!isFakeOverride) return false
val overriddenSymbols = overriddenSymbols
@OptIn(IrSymbolInternals::class)
return overriddenSymbols.isEmpty() || overriddenSymbols.any { it.owner.isIllegalFakeOverride() }
}
if (fakeOverrideOwnerLookupTag != null &&
firPropertySymbol is FirSyntheticPropertySymbol &&
originalProperty.isIllegalFakeOverride()
) {
// Fallback for a synthetic property complex case
return containingClassLookupTag.getIrCallableSymbol()
}
return if (unmatchedOwner && fakeOverrideOwnerLookupTag is ConeClassLookupTagWithFixedSymbol) {
fakeOverrideOwnerLookupTag.findIrFakeOverride(fir.name, originalProperty) as IrPropertySymbol
} else {
originalSymbol
}
}
fun getCachedIrProperty(property: FirProperty): IrProperty? {
return getCachedIrProperty(property, fakeOverrideOwnerLookupTag = null) {
signatureComposer.composeSignature(property)
}
return result.symbol
}
fun getCachedIrProperty(
property: FirProperty,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?,
signatureCalculator: () -> IdSignature?
signatureCalculator: () -> IdSignature? = { signatureComposer.composeSignature(property, fakeOverrideOwnerLookupTag) }
): IrProperty? {
@Suppress("NAME_SHADOWING")
val property = prepareProperty(property)
@@ -1043,69 +1009,6 @@ class Fir2IrDeclarationStorage(
}
}
private inline fun <
reified FS : FirCallableSymbol<*>,
reified F : FirCallableDeclaration,
I : IrSymbolOwner,
> getIrCallableSymbol(
firSymbol: FS,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?,
getCachedIrDeclaration: (firDeclaration: F, dispatchReceiverLookupTag: ConeClassLikeLookupTag?, () -> IdSignature?) -> I?,
createIrDeclaration: (parent: IrDeclarationParent?, origin: IrDeclarationOrigin) -> I,
createIrLazyDeclaration: (signature: IdSignature, lazyOwner: IrDeclarationParent, origin: IrDeclarationOrigin) -> I,
): IrSymbol {
val fir = firSymbol.fir as F
val irParent by lazy { findIrParent(fir, fakeOverrideOwnerLookupTag) }
val signature by lazy {
signatureComposer.composeSignature(
fir,
fakeOverrideOwnerLookupTag,
forceExpect = fakeOverrideOwnerLookupTag?.toSymbol(session)?.isExpect == true
)
}
synchronized(symbolTable.lock) {
getCachedIrDeclaration(fir, fakeOverrideOwnerLookupTag.takeIf { it !is ConeClassLookupTagWithFixedSymbol }) {
// Parent calculation provokes declaration calculation for some members from IrBuiltIns
@Suppress("UNUSED_EXPRESSION") irParent
signature
}?.let { return it.symbol }
val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED
val declarationOrigin = firSymbol.fir.computeIrOrigin(parentOrigin = parentOrigin)
when (val parent = irParent) {
is Fir2IrLazyClass -> {
assert(parentOrigin != IrDeclarationOrigin.DEFINED || configuration.allowNonCachedDeclarations) {
"Should not have reference to public API uncached property from source code"
}
signature?.let {
return createIrLazyDeclaration(it, parent, declarationOrigin).symbol
}
}
is IrLazyClass -> {
val unwrapped = fir.unwrapFakeOverrides()
if (unwrapped !== fir) {
when (unwrapped) {
is FirSimpleFunction -> {
return getIrFunctionSymbol(unwrapped.symbol)
}
is FirProperty -> {
return getIrPropertySymbol(unwrapped.symbol)
}
}
}
}
is IrExternalPackageFragment -> {
signature?.let {
return createIrLazyDeclaration(it, parent, declarationOrigin).symbol
}
}
}
return createIrDeclaration(irParent, declarationOrigin).apply {
callablesGenerator.setAndModifyParent((this as IrDeclaration), irParent)
}.symbol
}
}
// ------------------------------------ scripts ------------------------------------
fun getCachedIrScript(script: FirScript): IrScript? {
@@ -1241,16 +1144,6 @@ class Fir2IrDeclarationStorage(
)
}
private inline fun <reified S : IrSymbol, reified D : IrOverridableDeclaration<S>> ConeClassLookupTagWithFixedSymbol.findIrFakeOverride(
name: Name, originalDeclaration: IrOverridableDeclaration<S>
): IrSymbol? {
val dispatchReceiverIrClass =
classifierStorage.getOrCreateIrClass(toSymbol(session) as FirClassSymbol)
return dispatchReceiverIrClass.declarations.find {
it is D && it.isFakeOverride && it.name == name && it.overrides(originalDeclaration)
}?.symbol
}
companion object {
internal val ENUM_SYNTHETIC_NAMES = mapOf(
Name.identifier("values") to IrSyntheticBodyKind.ENUM_VALUES,
@@ -486,7 +486,7 @@ class Fir2IrVisitor(
override fun visitProperty(property: FirProperty, data: Any?): IrElement = whileAnalysing(session, property) {
if (property.isLocal) return visitLocalVariable(property)
val irProperty = declarationStorage.getCachedIrProperty(property)
val irProperty = declarationStorage.getCachedIrProperty(property, fakeOverrideOwnerLookupTag = null)
?: return IrErrorExpressionImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
IrErrorTypeImpl(null, emptyList(), Variance.INVARIANT),
@@ -207,6 +207,22 @@ class FakeOverrideGenerator(
baseFunctionSymbols[fakeOverride] = baseFirSymbolsForFakeOverride
}
internal fun calcBaseSymbolsForFakeOverrideProperty(
klass: FirClass,
fakeOverride: IrProperty,
originalSymbol: FirPropertySymbol,
) {
val scope = klass.unsubstitutedScope()
val classLookupTag = klass.symbol.toLookupTag()
val baseFirSymbolsForFakeOverride =
if (originalSymbol.shouldHaveComputedBaseSymbolsForClass(classLookupTag)) {
computeBaseSymbols(originalSymbol, FirTypeScope::getDirectOverriddenProperties, scope, classLookupTag)
} else {
listOf(originalSymbol)
}
basePropertySymbols[fakeOverride] = baseFirSymbolsForFakeOverride
}
private fun FirCallableSymbol<*>.shouldHaveComputedBaseSymbolsForClass(classLookupTag: ConeClassLikeLookupTag): Boolean =
fir.origin.fromSupertypes && dispatchReceiverClassLookupTagOrNull() == classLookupTag
@@ -402,6 +418,14 @@ class FakeOverrideGenerator(
) { declarationStorage.getIrPropertySymbol(it) as IrPropertySymbol }
}
internal fun getOverriddenSymbolsForFakeOverride(property: IrProperty): List<IrPropertySymbol>? {
val baseSymbols = basePropertySymbols[property] ?: return null
return getOverriddenSymbolsInSupertypes(
property,
baseSymbols
) { declarationStorage.getIrPropertySymbol(it) as IrPropertySymbol }
}
@OptIn(IrSymbolInternals::class)
private fun <I : IrDeclaration, S : IrSymbol, F : FirCallableSymbol<*>> getOverriddenSymbolsInSupertypes(
declaration: I,
@@ -55,6 +55,8 @@ import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.utils.addToStdlib.runUnless
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fir2IrComponents by components {
// ------------------------------------ package fragments ------------------------------------
@@ -105,6 +107,7 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi
function.isJavaOrEnhancement -> IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
else -> function.computeIrOrigin(predefinedOrigin, parentOrigin = (irParent as? IrDeclaration)?.origin)
}
val parentIsExternal = irParent.isExternalParent()
// We don't generate signatures for local classes
// We attempt to avoid signature generation for non-local classes, with the following exceptions:
// - special mode (generateSignatures) oriented on special backend modes
@@ -115,15 +118,15 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi
val signature =
runUnless(
isLocal ||
!configuration.linkViaSignatures && irParent !is Fir2IrLazyClass &&
!configuration.linkViaSignatures && !parentIsExternal &&
function.dispatchReceiverType?.isPrimitive != true && function.containerSource == null &&
updatedOrigin != IrDeclarationOrigin.FAKE_OVERRIDE && !function.isOverride
) {
signatureComposer.composeSignature(function, fakeOverrideOwnerLookupTag)
}
if (irParent is Fir2IrLazyClass && signature != null) {
if (parentIsExternal && signature != null) {
// For private functions signature is null, fallback to non-lazy function
return lazyDeclarationsGenerator.createIrLazyFunction(function as FirSimpleFunction, signature, irParent, updatedOrigin)
return lazyDeclarationsGenerator.createIrLazyFunction(function as FirSimpleFunction, signature, irParent!!, updatedOrigin)
}
val name = simpleFunction?.name
?: if (isLambda) SpecialNames.ANONYMOUS else SpecialNames.NO_NAME_PROVIDED
@@ -272,21 +275,22 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi
property.name in Fir2IrDeclarationStorage.ENUM_SYNTHETIC_NAMES
-> IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER
else -> property.computeIrOrigin(predefinedOrigin)
else -> property.computeIrOrigin(predefinedOrigin, parentOrigin = (irParent as? IrDeclaration)?.origin)
}
// See similar comments in createIrFunction above
val parentIsExternal = irParent.isExternalParent()
val signature =
runUnless(
isLocal ||
!configuration.linkViaSignatures && irParent !is Fir2IrLazyClass &&
!configuration.linkViaSignatures && !parentIsExternal &&
property.dispatchReceiverType?.isPrimitive != true && property.containerSource == null &&
origin != IrDeclarationOrigin.FAKE_OVERRIDE && !property.isOverride
) {
signatureComposer.composeSignature(property, fakeOverrideOwnerLookupTag)
}
if (irParent is Fir2IrLazyClass && signature != null) {
if (parentIsExternal && signature != null) {
// For private functions signature is null, fallback to non-lazy property
return lazyDeclarationsGenerator.createIrLazyProperty(property, signature, irParent, origin)
return lazyDeclarationsGenerator.createIrLazyProperty(property, signature, irParent!!, origin)
}
return property.convertWithOffsets { startOffset, endOffset ->
val result = declareIrProperty(signature) { symbol ->
@@ -401,6 +405,14 @@ 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],
@@ -62,8 +62,12 @@ class Fir2IrLazyDeclarationsGenerator(val components: Fir2IrComponents) : Fir2Ir
fun create(startOffset: Int, endOffset: Int, isPropertyForField: Boolean): Fir2IrLazyProperty {
val firContainingClass = (lazyParent as? Fir2IrLazyClass)?.fir
val isFakeOverride = !isPropertyForField && fir.isFakeOverride(firContainingClass)
// It is really required to create those properties with DEFINED origin
// Using `declarationOrigin` here (IR_EXTERNAL_JAVA_DECLARATION_STUB in particular) causes some tests to fail, including
// FirPsiBlackBoxCodegenTestGenerated.Reflection.Properties.testJavaStaticField
val originForProperty = if (isPropertyForField) IrDeclarationOrigin.DEFINED else declarationOrigin
return Fir2IrLazyProperty(
components, startOffset, endOffset, declarationOrigin,
components, startOffset, endOffset, originForProperty,
fir, firContainingClass, symbol, isFakeOverride
).apply {
this.parent = lazyParent
@@ -9,11 +9,8 @@ import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.isAnnotationClass
import org.jetbrains.kotlin.fir.backend.ConversionTypeOrigin
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
import org.jetbrains.kotlin.fir.backend.asCompileTimeIrInitializer
import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.backend.generators.generateOverriddenPropertySymbols
import org.jetbrains.kotlin.fir.backend.toIrConst
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
@@ -188,7 +185,7 @@ class Fir2IrLazyProperty(
fir.getter is FirDefaultPropertyGetter -> IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR
else -> origin
},
fir.getter, isSetter = false, fir, containingClass, symbol, isFakeOverride
fir.getter, isSetter = false, fir, containingClass, symbol, isFakeOverride, this.symbol
)
}.apply {
parent = this@Fir2IrLazyProperty.parent
@@ -216,7 +213,7 @@ class Fir2IrLazyProperty(
fir.setter is FirDefaultPropertySetter -> IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR
else -> origin
},
fir.setter, isSetter = true, fir, containingClass, symbol, isFakeOverride
fir.setter, isSetter = true, fir, containingClass, symbol, isFakeOverride, this.symbol
).apply {
parent = this@Fir2IrLazyProperty.parent
correspondingPropertySymbol = this@Fir2IrLazyProperty.symbol
@@ -228,6 +225,15 @@ class Fir2IrLazyProperty(
override var overriddenSymbols: List<IrPropertySymbol> by lazyVar(lock) {
if (containingClass == null) return@lazyVar emptyList()
if (isFakeOverride && parent is Fir2IrLazyClass) {
fakeOverrideGenerator.calcBaseSymbolsForFakeOverrideProperty(
containingClass, this, fir.symbol
)
fakeOverrideGenerator.getOverriddenSymbolsForFakeOverride(this)?.let {
assert(!it.contains(symbol)) { "Cannot add function $symbol to its own overriddenSymbols" }
return@lazyVar it
}
}
fir.generateOverriddenPropertySymbols(containingClass)
}
@@ -19,7 +19,9 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
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.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbolInternals
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.isFacadeClass
import org.jetbrains.kotlin.name.Name
@@ -35,7 +37,8 @@ class Fir2IrLazyPropertyAccessor(
private val firParentProperty: FirProperty,
firParentClass: FirRegularClass?,
symbol: IrSimpleFunctionSymbol,
isFakeOverride: Boolean
isFakeOverride: Boolean,
override var correspondingPropertySymbol: IrPropertySymbol?
) : AbstractFir2IrLazyFunction<FirCallableDeclaration>(components, startOffset, endOffset, origin, symbol, isFakeOverride) {
init {
symbol.bind(this)
@@ -110,7 +113,14 @@ class Fir2IrLazyPropertyAccessor(
override var overriddenSymbols: List<IrSimpleFunctionSymbol> by lazyVar(lock) {
if (firParentClass == null) return@lazyVar emptyList()
firParentProperty.generateOverriddenAccessorSymbols(firParentClass, !isSetter)
// If property accessor is created then corresponding property is definitely created too
@OptIn(IrSymbolInternals::class)
correspondingPropertySymbol!!.owner.overriddenSymbols.mapNotNull {
when (isSetter) {
false -> declarationStorage.findGetterOfProperty(it)
true -> declarationStorage.findSetterOfProperty(it)
}
}
}
override val initialSignatureFunction: IrFunction? by lazy {
@@ -1,4 +1,6 @@
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND_K2: JVM_IR
// ISSUE: KT-61941
// WITH_STDLIB
// IGNORE_CODEGEN_WITH_IR_FAKE_OVERRIDE_GENERATION: KT-61370