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

KT-62856
This commit is contained in:
Dmitriy Novozhilov
2023-11-14 15:43:41 +02:00
committed by Space Team
parent f0f8a9728e
commit 736201da1d
10 changed files with 254 additions and 212 deletions
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.backend
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.KtPsiSourceFileLinesMapping
@@ -23,16 +24,19 @@ import org.jetbrains.kotlin.fir.backend.generators.DataClassMembersGenerator
import org.jetbrains.kotlin.fir.backend.generators.addDeclarationToParent
import org.jetbrains.kotlin.fir.backend.generators.setParent
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.correspondingValueParameterFromPrimaryConstructor
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.declarations.utils.isSynthetic
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.extensions.declarationGenerators
import org.jetbrains.kotlin.fir.extensions.extensionService
import org.jetbrains.kotlin.fir.extensions.generatedMembers
import org.jetbrains.kotlin.fir.extensions.generatedNestedClassifiers
import org.jetbrains.kotlin.fir.java.javaElementFinder
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass
import org.jetbrains.kotlin.fir.references.toResolvedValueParameterSymbol
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.symbols.lazyDeclarationResolver
import org.jetbrains.kotlin.fir.types.resolvedType
@@ -51,9 +55,9 @@ import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode
import org.jetbrains.kotlin.ir.interpreter.transformer.transformConst
import org.jetbrains.kotlin.ir.overrides.IrFakeOverrideBuilder
import org.jetbrains.kotlin.ir.symbols.UnsafeDuringIrConstructionAPI
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorPublicSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionPublicSymbolImpl
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.util.KotlinMangler
import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl
import org.jetbrains.kotlin.ir.util.defaultType
@@ -198,7 +202,7 @@ class Fir2IrConverter(
private fun processFileAndClassMembers(file: FirFile) {
val irFile = declarationStorage.getIrFile(file)
for (declaration in file.declarations) {
processMemberDeclaration(declaration, null, irFile)
processMemberDeclaration(declaration, containingClass = null, irFile, delegateFieldToPropertyMap = null)
}
}
@@ -242,9 +246,12 @@ class Fir2IrConverter(
declarationStorage.createAndCacheIrConstructor(it.fir, { irClass }, isLocal = klass.isLocal)
}
}
val delegateFieldToPropertyMap = MultiMap<FirProperty, FirField>()
// At least on enum entry creation we may need a default constructor, so ctors should be converted first
for (declaration in syntheticPropertiesLast(allDeclarations)) {
processMemberDeclaration(declaration, klass, irClass)
processMemberDeclaration(declaration, klass, irClass, delegateFieldToPropertyMap)
}
// Add delegated members *before* fake override generations.
// Otherwise, fake overrides for delegated members, which are redundant, will be added.
@@ -467,11 +474,17 @@ class Fir2IrConverter(
/**
* This function creates IR declarations for callable members without filling their body
*
* @param delegateFieldToPropertyMap is needed to avoid problems with delegation to properties from primary constructor.
* The thing is that FirFields for delegates are declared before properties from the primary constructor, but in IR we don't
* create separate IrField for such fields and reuse the backing field of corresponding property.
* So, this map is used to postpone generation of delegated members until IR for corresponding property will be created
*/
private fun processMemberDeclaration(
declaration: FirDeclaration,
containingClass: FirClass?,
parent: IrDeclarationParent
parent: IrDeclarationParent,
delegateFieldToPropertyMap: MultiMap<FirProperty, FirField>?
) {
/*
* This function is needed to preserve the source order of declaration in file
@@ -512,7 +525,7 @@ class Fir2IrConverter(
}
for (scriptStatement in declaration.statements) {
if (scriptStatement is FirDeclaration) {
processMemberDeclaration(scriptStatement, null, irScript)
processMemberDeclaration(scriptStatement, containingClass = null, irScript, delegateFieldToPropertyMap = null)
}
}
}
@@ -528,15 +541,35 @@ class Fir2IrConverter(
) {
// Note: we have to do it, because backend without the feature
// cannot process Enum.entries properly
declarationStorage.getOrCreateIrProperty(declaration, parent, isLocal = isInLocalClass)
val irProperty = declarationStorage.createAndCacheIrProperty(declaration, parent)
delegateFieldToPropertyMap?.remove(declaration)?.let { delegateFields ->
val backingField = irProperty.backingField!!
for (delegateField in delegateFields) {
declarationStorage.recordDelegateFieldMappedToBackingField(delegateField, backingField.symbol)
delegatedMemberGenerator.generateWithBodiesIfNeeded(
firField = delegateField,
irField = backingField,
containingClass!!,
parent as IrClass
)
}
}
}
}
is FirField -> {
if (declaration.isSynthetic) {
callablesGenerator.createIrFieldAndDelegatedMembers(declaration, containingClass!!, parent as IrClass)
} else {
if (!declaration.isSynthetic) {
error("Unexpected non-synthetic field: ${declaration::class}")
}
requireNotNull(containingClass)
requireNotNull(delegateFieldToPropertyMap)
require(parent is IrClass)
val correspondingClassProperty = declaration.findCorrespondingDelegateProperty(containingClass)
if (correspondingClassProperty == null) {
val irField = declarationStorage.createDelegateIrField(declaration, parent)
delegatedMemberGenerator.generateWithBodiesIfNeeded(declaration, irField, containingClass, parent)
} else {
delegateFieldToPropertyMap.putValue(correspondingClassProperty, declaration)
}
}
is FirConstructor -> if (!declaration.isPrimary) {
// the primary constructor was already created in `processClassMembers` function
@@ -571,6 +604,16 @@ class Fir2IrConverter(
}
}
private fun FirField.findCorrespondingDelegateProperty(owner: FirClass): FirProperty? {
val initializer = this.initializer
if (initializer !is FirQualifiedAccessExpression) return null
if (initializer.explicitReceiver != null) return null
val resolvedSymbol = initializer.calleeReference.toResolvedValueParameterSymbol() ?: return null
return owner.declarations.filterIsInstance<FirProperty>().find {
it.correspondingValueParameterFromPrimaryConstructor == resolvedSymbol
}
}
companion object {
private fun evaluateConstants(irModuleFragment: IrModuleFragment, components: Fir2IrComponents) {
val fir2IrConfiguration = components.configuration
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.builtins.StandardNames.BUILT_INS_PACKAGE_FQ_NAMES
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
@@ -14,21 +13,26 @@ 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
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.declarations.utils.hasBackingField
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.descriptors.FirBuiltInsPackageFragment
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.Fir2IrLazyProperty
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
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.resolvedType
import org.jetbrains.kotlin.fir.types.toLookupTag
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.declarations.UNDEFINED_PARAMETER_INDEX
import org.jetbrains.kotlin.ir.declarations.*
@@ -50,7 +54,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.runIf
import org.jetbrains.kotlin.utils.threadLocal
import java.util.concurrent.ConcurrentHashMap
@OptIn(LeakedDeclarationCaches::class)
class Fir2IrDeclarationStorage(
private val components: Fir2IrComponents,
private val sourceModuleDescriptor: FirModuleDescriptor,
@@ -470,36 +473,6 @@ class Fir2IrDeclarationStorage(
return prepareProperty(symbol.fir).symbol
}
fun getOrCreateIrProperty(
property: FirProperty,
irParent: IrDeclarationParent?,
predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null
): IrProperty {
return getOrCreateIrProperty(property, { irParent }, predefinedOrigin, isLocal, fakeOverrideOwnerLookupTag)
}
private fun getOrCreateIrProperty(
property: FirProperty,
irParent: () -> IrDeclarationParent?,
predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null
): IrProperty {
@Suppress("NAME_SHADOWING")
val property = prepareProperty(property)
@OptIn(UnsafeDuringIrConstructionAPI::class)
getCachedIrPropertySymbol(property, fakeOverrideOwnerLookupTag)?.ownerIfBound()?.let { return it }
// See comment in [getOrCreateIrFunction]
if (fakeOverrideOwnerLookupTag != property.containingClassLookupTag()) {
generateLazyFakeOverrides(property.name, fakeOverrideOwnerLookupTag)
@OptIn(UnsafeDuringIrConstructionAPI::class)
getCachedIrPropertySymbol(property, fakeOverrideOwnerLookupTag)?.ownerIfBound()?.let { return it }
}
return createAndCacheIrProperty(property, irParent(), predefinedOrigin, isLocal, fakeOverrideOwnerLookupTag)
}
fun getOrCreateIrPropertyByPureField(
field: FirField,
irParent: IrDeclarationParent
@@ -509,32 +482,29 @@ class Fir2IrDeclarationStorage(
createAndCacheIrProperty(
field.toStubProperty(),
irParent,
fakeOverrideOwnerLookupTag = containingClassId?.toLookupTag()
isLocal = false,
fakeOverrideOwnerLookupTag = containingClassId?.toLookupTag(),
allowLazyDeclarationsCreation = true // pure fields exist only in java
)
}
}
@LeakedDeclarationCaches
fun createAndCacheIrProperty(
property: FirProperty,
irParent: IrDeclarationParent?,
predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null,
allowLazyDeclarationsCreation: Boolean = false
): IrProperty {
@Suppress("NAME_SHADOWING")
val property = prepareProperty(property)
val signature = runIf(!isLocal && configuration.linkViaSignatures) {
signatureComposer.composeSignature(property, fakeOverrideOwnerLookupTag)
}
val symbols = getIrPropertySymbols(property.symbol, fakeOverrideOwnerLookupTag, isLocal)
val symbols = createPropertySymbols(signature, property, fakeOverrideOwnerLookupTag)
val irProperty = callablesGenerator.createIrProperty(
property, irParent, symbols, predefinedOrigin, isLocal, fakeOverrideOwnerLookupTag
return callablesGenerator.createIrProperty(
property, irParent, symbols, predefinedOrigin, fakeOverrideOwnerLookupTag, allowLazyDeclarationsCreation
)
cacheIrProperty(property, irProperty, fakeOverrideOwnerLookupTag)
return irProperty
}
private fun createPropertySymbols(
@@ -572,21 +542,21 @@ class Fir2IrDeclarationStorage(
return PropertySymbols(propertySymbol, getterSymbol, setterSymbol, backingFieldSymbol)
}
private fun cacheIrProperty(
private fun cacheIrPropertySymbols(
property: FirProperty,
irProperty: IrProperty,
symbols: PropertySymbols,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?,
) {
val irPropertySymbol = irProperty.symbol
irProperty.backingField?.symbol?.let {
val irPropertySymbol = symbols.propertySymbol
symbols.backingFieldSymbol?.let {
backingFieldForPropertyCache[irPropertySymbol] = it
propertyForBackingFieldCache[it] = irPropertySymbol
}
irProperty.getter?.let {
getterForPropertyCache[irPropertySymbol] = it.symbol
symbols.getterSymbol.let {
getterForPropertyCache[irPropertySymbol] = it
}
irProperty.setter?.let {
setterForPropertyCache[irPropertySymbol] = it.symbol
symbols.setterSymbol?.let {
setterForPropertyCache[irPropertySymbol] = it
}
if (property.isFakeOverrideOrDelegated(fakeOverrideOwnerLookupTag)) {
val originalProperty = property.unwrapFakeOverridesOrDelegated()
@@ -594,9 +564,9 @@ class Fir2IrDeclarationStorage(
originalProperty.symbol,
fakeOverrideOwnerLookupTag ?: property.containingClassLookupTag()!!
)
irForFirSessionDependantDeclarationMap[key] = irProperty.symbol
irForFirSessionDependantDeclarationMap[key] = irPropertySymbol
} else {
propertyCache[property] = irProperty.symbol
propertyCache[property] = irPropertySymbol
}
}
@@ -623,17 +593,51 @@ class Fir2IrDeclarationStorage(
fun getIrPropertySymbol(
firPropertySymbol: FirPropertySymbol,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null,
isLocal: Boolean = false
): IrSymbol {
val firProperty = prepareProperty(firPropertySymbol.fir)
if (firProperty.isLocal) {
return localStorage.getDelegatedProperty(firProperty) ?: getIrVariableSymbol(firProperty)
val property = prepareProperty(firPropertySymbol.fir)
if (property.isLocal) {
return localStorage.getDelegatedProperty(property) ?: getIrVariableSymbol(property)
}
val result = getOrCreateIrProperty(
firProperty,
{ findIrParent(firProperty, fakeOverrideOwnerLookupTag) },
fakeOverrideOwnerLookupTag = fakeOverrideOwnerLookupTag
)
return result.symbol
getCachedIrPropertySymbol(property, fakeOverrideOwnerLookupTag)?.let { return it }
return getIrPropertySymbols(firPropertySymbol, fakeOverrideOwnerLookupTag, isLocal).propertySymbol
}
private fun getIrPropertySymbols(
firPropertySymbol: FirPropertySymbol,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null,
isLocal: Boolean
): PropertySymbols {
val property = prepareProperty(firPropertySymbol.fir)
getCachedIrPropertySymbols(property, fakeOverrideOwnerLookupTag)?.let { return it }
return createAndCacheIrPropertySymbols(property, fakeOverrideOwnerLookupTag, isLocal)
}
private fun createAndCacheIrPropertySymbols(
property: FirProperty,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?,
isLocal: Boolean
): PropertySymbols {
val signature = runIf(!isLocal && configuration.linkViaSignatures) {
signatureComposer.composeSignature(property, fakeOverrideOwnerLookupTag)
}
val symbols = createPropertySymbols(signature, property, fakeOverrideOwnerLookupTag)
val irParent = findIrParent(property, fakeOverrideOwnerLookupTag)
if (irParent?.isExternalParent() == true) {
callablesGenerator.createIrProperty(
property,
irParent,
symbols,
predefinedOrigin = property.computeExternalOrigin(),
allowLazyDeclarationsCreation = true
).also {
check(it is Fir2IrLazyProperty)
}
}
cacheIrPropertySymbols(property, symbols, fakeOverrideOwnerLookupTag)
return symbols
}
fun getCachedIrPropertySymbol(
@@ -653,6 +657,20 @@ class Fir2IrDeclarationStorage(
}
}
private fun getCachedIrPropertySymbols(
property: FirProperty,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?,
signatureCalculator: () -> IdSignature? = { signatureComposer.composeSignature(property, fakeOverrideOwnerLookupTag) }
): PropertySymbols? {
val propertySymbol = getCachedIrPropertySymbol(property, fakeOverrideOwnerLookupTag, signatureCalculator) ?: return null
return PropertySymbols(
propertySymbol,
findGetterOfProperty(propertySymbol)!!,
findSetterOfProperty(propertySymbol),
findBackingFieldOfProperty(propertySymbol)
)
}
fun findGetterOfProperty(propertySymbol: IrPropertySymbol): IrSimpleFunctionSymbol? {
return getterForPropertyCache[propertySymbol]
}
@@ -741,7 +759,7 @@ class Fir2IrDeclarationStorage(
propertyCache[fir]?.ownerIfBound()?.let { return it.backingField!!.symbol }
val irParent = findIrParent(fir, fakeOverrideOwnerLookupTag = null)
val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED
createAndCacheIrProperty(fir, irParent, predefinedOrigin = parentOrigin).backingField!!.symbol
createAndCacheIrProperty(fir, irParent, predefinedOrigin = parentOrigin, isLocal = false).backingField!!.symbol
}
else -> {
getIrVariableSymbol(fir)
@@ -753,32 +771,20 @@ class Fir2IrDeclarationStorage(
return fieldCache[field]
}
fun recordDelegateFieldMappedToBackingField(field: FirField, irFieldSymbol: IrFieldSymbol) {
fieldCache[field] = irFieldSymbol
}
fun getCachedIrFieldStaticFakeOverrideSymbolByDeclaration(field: FirField): IrFieldSymbol? {
val ownerLookupTag = field.containingClassLookupTag() ?: return null
return fieldStaticOverrideCache[FieldStaticOverrideKey(ownerLookupTag, field.name)]
}
internal fun getOrCreateDelegateIrField(field: FirField, owner: FirClass, irClass: IrClass): IrField {
val initializer = field.initializer
if (initializer is FirQualifiedAccessExpression && initializer.explicitReceiver == null) {
val resolvedSymbol = initializer.calleeReference.toResolvedValueParameterSymbol()
if (resolvedSymbol is FirValueParameterSymbol) {
val name = resolvedSymbol.name
val constructorProperty = owner.declarations.filterIsInstance<FirProperty>().find {
it.name == name && it.source?.kind is KtFakeSourceElementKind.PropertyFromParameter
}
if (constructorProperty != null) {
val irProperty = getOrCreateIrProperty(constructorProperty, irClass)
val backingField = irProperty.backingField!!
fieldCache[field] = backingField.symbol
return backingField
}
}
}
internal fun createDelegateIrField(field: FirField, irClass: IrClass): IrField {
return createAndCacheIrField(
field,
irParent = irClass,
type = initializer?.resolvedType ?: field.returnTypeRef.coneType,
type = field.initializer?.resolvedType ?: field.returnTypeRef.coneType,
origin = IrDeclarationOrigin.DELEGATE
)
}
@@ -14,9 +14,12 @@ import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer
import org.jetbrains.kotlin.ir.linkage.IrProvider
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -177,8 +180,7 @@ class FirIrProvider(val components: Fir2IrComponents) : IrProvider {
shouldNotBeCalled()
}
SymbolKind.PROPERTY_SYMBOL -> {
val firProperty = firDeclaration as FirProperty
declarationStorage.getOrCreateIrProperty(firProperty, parent)
shouldNotBeCalled()
}
SymbolKind.FIELD_SYMBOL -> {
val firField = firDeclaration as FirField
@@ -11,13 +11,11 @@ import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.scopes.getFunctions
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
@@ -705,16 +703,7 @@ class IrBuiltInsOverFir(
private fun findProperty(propertySymbol: FirPropertySymbol): IrPropertySymbol {
propertySymbol.lazyResolveToPhase(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE)
val irParent = findIrParent(propertySymbol)
return components.declarationStorage.getOrCreateIrProperty(propertySymbol.fir, irParent).symbol
}
private fun findIrParent(firSymbol: FirCallableSymbol<*>): IrDeclarationParent? {
return when (val containingClassLookupTag = firSymbol.containingClassLookupTag()) {
null -> components.declarationStorage.getIrExternalPackageFragment(firSymbol.callableId.packageName, firSymbol.moduleData)
else -> components.classifierStorage.findIrClass(containingClassLookupTag)
}
return components.declarationStorage.getIrPropertySymbol(propertySymbol) as IrPropertySymbol
}
private val IrClassSymbol.defaultTypeWithoutArguments: IrSimpleType
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isLocalClassOrAnonymousObject
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.scope
import org.jetbrains.kotlin.fir.scopes.*
@@ -27,8 +28,10 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.UnsafeDuringIrConstructionAPI
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.isNullable
import org.jetbrains.kotlin.ir.types.isSubtypeOfClass
import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -94,6 +97,13 @@ class DelegatedMemberGenerator(private val components: Fir2IrComponents) : Fir2I
bodiesInfo.clear()
}
fun generateWithBodiesIfNeeded(firField: FirField, irField: IrField, firSubClass: FirClass, subClass: IrClass) {
delegatedMemberGenerator.generate(irField, firField, firSubClass, subClass)
if (firSubClass.isLocalClassOrAnonymousObject()) {
delegatedMemberGenerator.generateBodies()
}
}
// Generate delegated members for [subClass]. The synthetic field [irField] has the super interface type.
fun generate(irField: IrField, firField: FirField, firSubClass: FirClass, subClass: IrClass) {
val subClassScope = firSubClass.unsubstitutedScope()
@@ -345,7 +355,7 @@ class DelegatedMemberGenerator(private val components: Fir2IrComponents) : Fir2I
firSubClass: FirClass,
firDelegateProperty: FirProperty
): IrProperty {
val delegateProperty = declarationStorage.getOrCreateIrProperty(
val delegateProperty = declarationStorage.createAndCacheIrProperty(
firDelegateProperty, subClass, predefinedOrigin = IrDeclarationOrigin.DELEGATED_MEMBER,
fakeOverrideOwnerLookupTag = firSubClass.symbol.toLookupTag()
)
@@ -8,7 +8,10 @@ package org.jetbrains.kotlin.fir.backend.generators
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.declarations.utils.allowsToHaveFakeOverride
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.isRealOwnerOf
import org.jetbrains.kotlin.fir.resolve.toSymbol
@@ -16,7 +19,10 @@ import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.scopes.impl.FirFakeOverrideGenerator
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFieldSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.*
@@ -129,11 +135,18 @@ class FakeOverrideGenerator(
useSiteOrStaticScope.processPropertiesByName(name) { propertyOrFieldSymbol ->
when (propertyOrFieldSymbol) {
is FirPropertySymbol -> {
@OptIn(LeakedDeclarationCaches::class)
createFakeOverriddenIfNeeded(
firClass, irClass, isLocal, propertyOrFieldSymbol,
declarationStorage::getCachedIrPropertySymbol,
declarationStorage::createAndCacheIrProperty,
{ property, irParent, predefinedOrigin, isLocal ->
declarationStorage.createAndCacheIrProperty(
property,
irParent,
predefinedOrigin,
isLocal,
allowLazyDeclarationsCreation = true
)
},
createFakeOverrideSymbol = { firProperty, callableSymbol ->
val symbolForOverride =
FirFakeOverrideGenerator.createSymbolForSubstitutionOverride(callableSymbol, firClass.symbol.classId)
@@ -538,7 +551,6 @@ class FakeOverrideGenerator(
}
context(Fir2IrComponents)
@OptIn(UnsafeDuringIrConstructionAPI::class)
internal fun FirProperty.generateOverriddenAccessorSymbols(containingClass: FirClass, isGetter: Boolean): List<IrSimpleFunctionSymbol> {
val scope = containingClass.unsubstitutedScope()
scope.processPropertiesByName(name) {}
@@ -555,8 +567,8 @@ internal fun FirProperty.generateOverriddenAccessorSymbols(containingClass: FirC
for (overriddenIrPropertySymbol in fakeOverrideGenerator.getOverriddenSymbolsInSupertypes(overriddenSymbol, superClasses)) {
val overriddenIrAccessorSymbol =
if (isGetter) overriddenIrPropertySymbol.owner.getter?.symbol
else overriddenIrPropertySymbol.owner.setter?.symbol
if (isGetter) declarationStorage.findGetterOfProperty(overriddenIrPropertySymbol)
else declarationStorage.findSetterOfProperty(overriddenIrPropertySymbol)
if (overriddenIrAccessorSymbol != null) {
assert(overriddenIrAccessorSymbol != symbol) { "Cannot add property $overriddenIrAccessorSymbol to its own overriddenSymbols" }
overriddenSet += overriddenIrAccessorSymbol
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyConstructor
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyProperty
import org.jetbrains.kotlin.fir.references.toResolvedBaseSymbol
import org.jetbrains.kotlin.fir.resolve.calls.FirSimpleSyntheticPropertySymbol
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isLocalClassOrAnonymousObject
import org.jetbrains.kotlin.fir.resolve.isKFunctionInvoke
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
@@ -51,7 +50,6 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.NameUtils
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
@@ -228,8 +226,8 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi
irParent: IrDeclarationParent?,
symbols: PropertySymbols,
predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null,
allowLazyDeclarationsCreation: Boolean
): IrProperty = convertCatching(property) {
val origin = when {
!predefinedOrigin.isExternal &&
@@ -245,16 +243,12 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi
}
// See similar comments in createIrFunction above
val parentIsExternal = irParent.isExternalParent()
val signature =
runUnless(
isLocal ||
!configuration.linkViaSignatures && !parentIsExternal &&
property.dispatchReceiverType?.isPrimitive != true && property.containerSource == null &&
origin != IrDeclarationOrigin.FAKE_OVERRIDE && !property.isOverride
) {
signatureComposer.composeSignature(property, fakeOverrideOwnerLookupTag)
if (parentIsExternal) {
if (!allowLazyDeclarationsCreation) {
error("Lazy properties should be processed in Fir2IrDeclarationStorage")
}
if (parentIsExternal && signature != null) {
@OptIn(UnsafeDuringIrConstructionAPI::class)
if (symbols.propertySymbol.isBound) return symbols.propertySymbol.owner
// For private functions signature is null, fallback to non-lazy property
return lazyDeclarationsGenerator.createIrLazyProperty(property, irParent!!, symbols, origin)
}
@@ -532,18 +526,6 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi
else -> Visibilities.Private
}
fun createIrFieldAndDelegatedMembers(field: FirField, owner: FirClass, irClass: IrClass): IrField? {
// Either take a corresponding constructor property backing field,
// or create a separate delegate field
val irField = declarationStorage.getOrCreateDelegateIrField(field, owner, irClass)
delegatedMemberGenerator.generate(irField, field, owner, irClass)
if (owner.isLocalClassOrAnonymousObject()) {
delegatedMemberGenerator.generateBodies()
}
// If it's a property backing field, it should not be added to the class in Fir2IrConverter, so it's not returned
return irField.takeIf { it.correspondingPropertySymbol == null }
}
internal fun createIrField(
field: FirField,
irParent: IrDeclarationParent?,
@@ -5,13 +5,13 @@
package org.jetbrains.kotlin.fir.backend.generators
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.backend.convertWithOffsets
import org.jetbrains.kotlin.fir.backend.isStubPropertyForPureField
import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
import org.jetbrains.kotlin.fir.lazy.*
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.unwrapUseSiteSubstitutionOverrides
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
@@ -214,7 +214,9 @@ class Fir2IrLazyClass(
symbol.containingClassLookupTag() != ownerLookupTag -> {}
symbol !is FirPropertySymbol -> {}
else -> {
result += declarationStorage.getOrCreateIrProperty(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.getIrPropertySymbol(symbol, lookupTag).owner as IrProperty
}
}
}
@@ -109,70 +109,67 @@ class Fir2IrLazyProperty(
}
}
override var backingField: IrField? by lazyVar(lock) {
when {
fir.hasExplicitBackingField -> {
val backingFieldType = with(typeConverter) {
fir.backingField?.returnTypeRef?.toIrType()
}
val initializer = fir.backingField?.initializer ?: fir.initializer
val visibility = fir.backingField?.visibility ?: fir.visibility
callablesGenerator.createBackingField(
this@Fir2IrLazyProperty,
fir,
IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
symbols.backingFieldSymbol!!,
components.visibilityConverter.convertToDescriptorVisibility(visibility),
fir.name,
fir.isVal,
initializer,
backingFieldType
).also { field ->
field.initializer = toIrInitializer(initializer)
}
override var backingField: IrField? = when {
fir.hasExplicitBackingField -> {
val backingFieldType = with(typeConverter) {
fir.backingField?.returnTypeRef?.toIrType()
}
extensions.hasBackingField(fir, session) && origin != IrDeclarationOrigin.FAKE_OVERRIDE -> {
callablesGenerator.createBackingField(
this@Fir2IrLazyProperty,
fir,
IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
symbols.backingFieldSymbol!!,
components.visibilityConverter.convertToDescriptorVisibility(fir.visibility),
fir.name,
fir.isVal,
fir.initializer,
type
).also { field ->
field.initializer = toIrInitializer(fir.initializer)
}
val initializer = fir.backingField?.initializer ?: fir.initializer
val visibility = fir.backingField?.visibility ?: fir.visibility
callablesGenerator.createBackingField(
this@Fir2IrLazyProperty,
fir,
IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
symbols.backingFieldSymbol!!,
components.visibilityConverter.convertToDescriptorVisibility(visibility),
fir.name,
fir.isVal,
initializer,
backingFieldType
).also { field ->
field.initializer = toIrInitializer(initializer)
}
fir.delegate != null -> {
callablesGenerator.createBackingField(
this@Fir2IrLazyProperty,
fir,
IrDeclarationOrigin.PROPERTY_DELEGATE,
symbols.backingFieldSymbol!!,
components.visibilityConverter.convertToDescriptorVisibility(fir.visibility),
NameUtils.propertyDelegateName(fir.name),
true,
fir.delegate
)
}
else -> {
null
}
}?.apply {
this.parent = this@Fir2IrLazyProperty.parent
this.annotations = fir.backingField?.annotations?.mapNotNull {
callGenerator.convertToIrConstructorCall(it) as? IrConstructorCall
}.orEmpty()
}
extensions.hasBackingField(fir, session) && origin != IrDeclarationOrigin.FAKE_OVERRIDE -> {
callablesGenerator.createBackingField(
this@Fir2IrLazyProperty,
fir,
IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
symbols.backingFieldSymbol!!,
components.visibilityConverter.convertToDescriptorVisibility(fir.visibility),
fir.name,
fir.isVal,
fir.initializer,
type
).also { field ->
field.initializer = toIrInitializer(fir.initializer)
}
}
fir.delegate != null -> {
callablesGenerator.createBackingField(
this@Fir2IrLazyProperty,
fir,
IrDeclarationOrigin.PROPERTY_DELEGATE,
symbols.backingFieldSymbol!!,
components.visibilityConverter.convertToDescriptorVisibility(fir.visibility),
NameUtils.propertyDelegateName(fir.name),
true,
fir.delegate
)
}
else -> {
null
}
}?.apply {
this.parent = this@Fir2IrLazyProperty.parent
this.annotations = fir.backingField?.annotations?.mapNotNull {
callGenerator.convertToIrConstructorCall(it) as? IrConstructorCall
}.orEmpty()
}
override var getter: IrSimpleFunction? by lazyVar(lock) {
Fir2IrLazyPropertyAccessor(
components, startOffset, endOffset,
origin = when {
override var getter: IrSimpleFunction? = Fir2IrLazyPropertyAccessor(
components, startOffset, endOffset,
origin =when {
origin == IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB -> origin
fir.delegate != null -> IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR
origin == IrDeclarationOrigin.FAKE_OVERRIDE -> origin
@@ -185,16 +182,15 @@ class Fir2IrLazyProperty(
firParentProperty = fir,
firParentClass = containingClass,
symbol = symbols.getterSymbol,
parent = this@Fir2IrLazyProperty.parent,
parent = this@Fir2IrLazyProperty.parent,
isFakeOverride = isFakeOverride,
correspondingPropertySymbol = this.symbol
correspondingPropertySymbol = this.symbol
).apply {
classifiersGenerator.setTypeParameters(this, this@Fir2IrLazyProperty.fir, ConversionTypeOrigin.DEFAULT)
}
classifiersGenerator.setTypeParameters(this, this@Fir2IrLazyProperty.fir, ConversionTypeOrigin.DEFAULT)
}
override var setter: IrSimpleFunction? by lazyVar(lock) {
if (!fir.isVar) return@lazyVar null
override var setter: IrSimpleFunction? = run {
if (!fir.isVar) return@run null
Fir2IrLazyPropertyAccessor(
components, startOffset, endOffset,
origin = when {