diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt index 8fa621bab55..0b4012f7007 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt @@ -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() + // 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? ) { /* * 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().find { + it.correspondingValueParameterFromPrimaryConstructor == resolvedSymbol + } + } + companion object { private fun evaluateConstants(irModuleFragment: IrModuleFragment, components: Fir2IrComponents) { val fir2IrConfiguration = components.configuration 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 4f83e793830..3b0b6874534 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 @@ -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().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 ) } 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 898aa78ac12..6ae09523e92 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 @@ -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 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 683f0887eb0..097abec1ee1 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 @@ -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 diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DelegatedMemberGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DelegatedMemberGenerator.kt index 9a2597f8ff2..b7c0d7e6858 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DelegatedMemberGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DelegatedMemberGenerator.kt @@ -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() ) 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 1c92a63fea0..50a9f86c74e 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 @@ -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 { 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 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 25b4b55845e..98b35fcc2ee 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 @@ -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?, 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 8e2a1fabff3..fe8fb0fea01 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 @@ -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 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 d8c34d6154b..b1843e3a9d0 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 @@ -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 } } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt index 2a68f08da1f..99138f06c32 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt @@ -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 {