From 771b44fd02bfe696afe58f25184156f7c2674f11 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Tue, 29 Aug 2023 12:31:46 +0300 Subject: [PATCH] [FIR2IR] Extract logic of IR declarations generation into separate component. Part 11 Group methods of Fir2IrDeclarationStorage and Fir2IrCallableDeclarationsGenerator by types of declarations they are working with. This commit contains nothing but just moving code in borders of the same file --- .../fir/backend/Fir2IrDeclarationStorage.kt | 1012 +++++++++-------- .../Fir2IrCallableDeclarationsGenerator.kt | 858 +++++++------- 2 files changed, 966 insertions(+), 904 deletions(-) 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 bccea24edec..85c35d140c1 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 @@ -154,33 +154,7 @@ class Fir2IrDeclarationStorage( private val localStorage: Fir2IrLocalCallableStorage by threadLocal { Fir2IrLocalCallableStorage() } - @OptIn(IrSymbolInternals::class) - private fun areCompatible(firFunction: FirFunction, irFunction: IrFunction): Boolean { - if (firFunction is FirSimpleFunction && irFunction is IrSimpleFunction) { - if (irFunction.name != firFunction.name) return false - } - return irFunction.valueParameters.size == firFunction.valueParameters.size && - irFunction.valueParameters.zip(firFunction.valueParameters).all { (irParameter, firParameter) -> - val irType = irParameter.type - val firType = firParameter.returnTypeRef.coneType - if (irType is IrSimpleType) { - when (val irClassifierSymbol = irType.classifier) { - is IrTypeParameterSymbol -> { - firType is ConeTypeParameterType - } - is IrClassSymbol -> { - val irClass = irClassifierSymbol.owner - firType is ConeClassLikeType && irClass.name == firType.lookupTag.name - } - is IrScriptSymbol -> { - false - } - } - } else { - false - } - } - } + // ------------------------------------ preprocessing ------------------------------------ internal fun preCacheBuiltinClassMembers(firClass: FirRegularClass, irClass: IrClass) { for (declaration in firClass.declarations) { @@ -220,44 +194,26 @@ class Fir2IrDeclarationStorage( } } - fun registerFile(firFile: FirFile, irFile: IrFile) { - fileCache[firFile] = irFile - } + // ------------------------------------ package fragments ------------------------------------ - fun getIrFile(firFile: FirFile): IrFile { - return fileCache[firFile]!! - } - - fun enterScope(symbol: IrSymbol) { - symbolTable.enterScope(symbol) - if (symbol is IrSimpleFunctionSymbol || - symbol is IrConstructorSymbol || - symbol is IrAnonymousInitializerSymbol || - symbol is IrPropertySymbol || - symbol is IrEnumEntrySymbol || - symbol is IrScriptSymbol - ) { - localStorage.enterCallable() + fun getIrExternalPackageFragment( + fqName: FqName, + firOrigin: FirDeclarationOrigin = FirDeclarationOrigin.Library + ): IrExternalPackageFragment { + val fragments = fragmentCache.getOrPut(fqName) { + val fragmentForDependencies = callablesGenerator.createExternalPackageFragment( + fqName, FirModuleDescriptor(session, moduleDescriptor.builtIns) + ) + val fragmentForPrecompiledBinaries = callablesGenerator.createExternalPackageFragment(fqName, moduleDescriptor) + ExternalPackageFragments(fragmentForDependencies, fragmentForPrecompiledBinaries) } - } - - fun leaveScope(symbol: IrSymbol) { - if (symbol is IrSimpleFunctionSymbol || - symbol is IrConstructorSymbol || - symbol is IrAnonymousInitializerSymbol || - symbol is IrPropertySymbol || - symbol is IrEnumEntrySymbol || - symbol is IrScriptSymbol - ) { - localStorage.leaveCallable() + // Make sure that external package fragments have a different module descriptor. The module descriptors are compared + // to determine if objects need regeneration because they are from different modules. + // But keep original module descriptor for the fragments coming from parts compiled on the previous incremental step + return when (firOrigin) { + FirDeclarationOrigin.Precompiled -> fragments.fragmentForPrecompiledBinaries + else -> fragments.fragmentForDependencies } - symbolTable.leaveScope(symbol) - } - - inline fun withScope(symbol: IrSymbol, crossinline block: () -> Unit) { - enterScope(symbol) - block() - leaveScope(symbol) } private fun getIrExternalOrBuiltInsPackageFragment(fqName: FqName, firOrigin: FirDeclarationOrigin): IrExternalPackageFragment { @@ -271,89 +227,14 @@ class Fir2IrDeclarationStorage( } } - fun getIrExternalPackageFragment( - fqName: FqName, - firOrigin: FirDeclarationOrigin = FirDeclarationOrigin.Library - ): IrExternalPackageFragment { - val fragments = fragmentCache.getOrPut(fqName) { - ExternalPackageFragments( - fragmentForDependencies = callablesGenerator.createExternalPackageFragment(fqName, FirModuleDescriptor(session, moduleDescriptor.builtIns)), - fragmentForPrecompiledBinaries = callablesGenerator.createExternalPackageFragment(fqName, moduleDescriptor) - ) - } - // Make sure that external package fragments have a different module descriptor. The module descriptors are compared - // to determine if objects need regeneration because they are from different modules. - // But keep original module descriptor for the fragments coming from parts compiled on the previous incremental step - return when (firOrigin) { - FirDeclarationOrigin.Precompiled -> fragments.fragmentForPrecompiledBinaries - else -> fragments.fragmentForDependencies - } + // ------------------------------------ files ------------------------------------ + + fun registerFile(firFile: FirFile, irFile: IrFile) { + fileCache[firFile] = irFile } - internal fun findIrParent( - packageFqName: FqName, - parentLookupTag: ConeClassLikeLookupTag?, - firBasedSymbol: FirBasedSymbol<*>, - firOrigin: FirDeclarationOrigin - ): IrDeclarationParent? { - if (parentLookupTag != null) { - return classifierStorage.findIrClass(parentLookupTag) - } - - val parentPackage = when (firBasedSymbol) { - is FirCallableSymbol<*> -> { - getIrExternalPackageFragment(packageFqName, firOrigin) - } - else -> { - // TODO: All classes from BUILT_INS_PACKAGE_FQ_NAMES are considered built-ins now, - // which is not exact and can lead to some problems - getIrExternalOrBuiltInsPackageFragment(packageFqName, firOrigin) - } - } - - val firProviderForSymbol = firBasedSymbol.moduleData.session.firProvider - val containerFile = when (firBasedSymbol) { - is FirCallableSymbol -> firProviderForSymbol.getFirCallableContainerFile(firBasedSymbol) - is FirClassLikeSymbol -> firProviderForSymbol.getFirClassifierContainerFileIfAny(firBasedSymbol) - else -> error("Unknown symbol: $firBasedSymbol") - } - - if (containerFile != null) { - val existingFile = fileCache[containerFile] - if (existingFile != null) { - return existingFile - } - - // Sudden declarations do not go through IR lowering process, - // so the parent file isn't replaced with a facade class, as in 'FileClassLowering'. - if (configuration.allowNonCachedDeclarations && firBasedSymbol is FirCallableSymbol<*>) { - val psiFile = containerFile.psi?.containingFile - if (psiFile is KtFile) { - val fileClassInfo = JvmFileClassUtil.getFileClassInfoNoResolve(psiFile) - val className = JvmClassName.byFqNameWithoutInnerClasses(fileClassInfo.fileClassFqName) - - val facadeClassName: JvmClassName? - val declarationOrigin: IrDeclarationOrigin - - if (fileClassInfo.withJvmMultifileClass) { - facadeClassName = JvmClassName.byFqNameWithoutInnerClasses(fileClassInfo.facadeClassFqName) - declarationOrigin = IrDeclarationOrigin.JVM_MULTIFILE_CLASS - } else { - facadeClassName = null - declarationOrigin = IrDeclarationOrigin.FILE_CLASS - } - - val facadeShortName = className.fqNameForClassNameWithoutDollars.shortName() - val containerSource = NonCachedSourceFacadeContainerSource(className, facadeClassName) - return NonCachedSourceFileFacadeClass(declarationOrigin, facadeShortName, containerSource).apply { - parent = parentPackage - createParameterDeclarations() - } - } - } - } - - return parentPackage + fun getIrFile(firFile: FirFile): IrFile { + return fileCache[firFile]!! } internal class NonCachedSourceFileFacadeClass( @@ -378,21 +259,7 @@ class Fir2IrDeclarationStorage( override fun getContainingFile(): SourceFile = SourceFile.NO_SOURCE_FILE } - private fun findIrParent(callableDeclaration: FirCallableDeclaration): IrDeclarationParent? { - val firBasedSymbol = callableDeclaration.symbol - val callableId = firBasedSymbol.callableId - val callableOrigin = callableDeclaration.origin - return findIrParent(callableId.packageName, callableDeclaration.containingClassLookupTag(), firBasedSymbol, callableOrigin) - } - - fun T.putParametersInScope(function: FirFunction): T { - val contextReceivers = function.contextReceiversForFunctionOrContainingProperty() - - for ((firParameter, irParameter) in function.valueParameters.zip(valueParameters.drop(contextReceivers.size))) { - localStorage.putParameter(firParameter, irParameter) - } - return this - } + // ------------------------------------ functions ------------------------------------ fun getCachedIrFunction(function: FirFunction): IrSimpleFunction? { return if (function is FirSimpleFunction) getCachedIrFunction(function) @@ -423,13 +290,6 @@ class Fir2IrDeclarationStorage( return cachedIrCallable } - internal fun cacheDelegationFunction(function: FirSimpleFunction, irFunction: IrSimpleFunction) { - functionCache[function] = irFunction - delegatedReverseCache[irFunction] = function - } - - fun originalDeclarationForDelegated(irDeclaration: IrDeclaration): FirDeclaration? = delegatedReverseCache[irDeclaration] - fun getOrCreateIrFunction( function: FirFunction, irParent: IrDeclarationParent?, @@ -482,15 +342,22 @@ class Fir2IrDeclarationStorage( } } - fun getOrCreateIrAnonymousInitializer( - anonymousInitializer: FirAnonymousInitializer, - containingIrClass: IrClass, - ): IrAnonymousInitializer { - return initializerCache.computeIfAbsent(anonymousInitializer) { - callablesGenerator.createIrAnonymousInitializer(anonymousInitializer, containingIrClass) + fun T.putParametersInScope(function: FirFunction): T { + val contextReceivers = function.contextReceiversForFunctionOrContainingProperty() + + for ((firParameter, irParameter) in function.valueParameters.zip(valueParameters.drop(contextReceivers.size))) { + localStorage.putParameter(firParameter, irParameter) } + return this } + internal fun cacheDelegationFunction(function: FirSimpleFunction, irFunction: IrSimpleFunction) { + functionCache[function] = irFunction + delegatedReverseCache[irFunction] = function + } + + // ------------------------------------ constructors ------------------------------------ + @OptIn(IrSymbolInternals::class) fun getCachedIrConstructor( constructor: FirConstructor, @@ -520,6 +387,36 @@ class Fir2IrDeclarationStorage( constructorCache[constructor] = irConstructor } + fun getIrConstructorSymbol(firConstructorSymbol: FirConstructorSymbol): IrConstructorSymbol { + val fir = firConstructorSymbol.fir + return getIrCallableSymbol( + firConstructorSymbol, + fakeOverrideOwnerLookupTag = null, + getCachedIrDeclaration = { constructor: FirConstructor, _, calculator -> getCachedIrConstructor(constructor, calculator) }, + createIrDeclaration = { parent, origin -> + callablesGenerator.createIrConstructor(fir, parent as IrClass, predefinedOrigin = origin) + }, + createIrLazyDeclaration = { signature, lazyParent, declarationOrigin -> + val symbol = Fir2IrConstructorSymbol(signature) + val irConstructor = fir.convertWithOffsets { startOffset, endOffset -> + symbolTable.declareConstructor(signature, { symbol }) { + Fir2IrLazyConstructor( + components, startOffset, endOffset, declarationOrigin, fir, symbol + ).apply { + parent = lazyParent + } + } + } + constructorCache[fir] = irConstructor + // NB: this is needed to prevent recursions in case of self bounds + (irConstructor as Fir2IrLazyConstructor).prepareTypeParameters() + irConstructor + }, + ) as IrConstructorSymbol + } + + // ------------------------------------ properties ------------------------------------ + fun getOrCreateIrProperty( property: FirProperty, irParent: IrDeclarationParent?, @@ -605,32 +502,59 @@ class Fir2IrDeclarationStorage( } } - fun findGetterOfProperty(propertySymbol: IrPropertySymbol): IrSimpleFunctionSymbol? { - return getterForPropertyCache[propertySymbol] - } + @OptIn(IrSymbolInternals::class) + fun getIrPropertySymbol( + firPropertySymbol: FirPropertySymbol, + fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null, + ): IrSymbol { + val fir = firPropertySymbol.fir + if (fir.isLocal) { + return localStorage.getDelegatedProperty(fir)?.symbol ?: getIrVariableSymbol(fir) + } + val containingClassLookupTag = firPropertySymbol.containingClassLookupTag() + val unmatchedOwner = fakeOverrideOwnerLookupTag != containingClassLookupTag + if (unmatchedOwner) { + generateLazyFakeOverrides(fir.name, fakeOverrideOwnerLookupTag) + } - fun findSetterOfProperty(propertySymbol: IrPropertySymbol): IrSimpleFunctionSymbol? { - return setterForPropertyCache[propertySymbol] - } + 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) + } + }, + ) - fun findBackingFieldOfProperty(propertySymbol: IrPropertySymbol): IrFieldSymbol? { - return backingFieldForPropertyCache[propertySymbol] - } + val originalSymbol = fakeOverrideOwnerLookupTag.getIrCallableSymbol() + val originalProperty = originalSymbol.owner as IrProperty - fun findPropertyForBackingField(fieldSymbol: IrFieldSymbol): IrPropertySymbol? { - return propertyForBackingFieldCache[fieldSymbol] - } + fun IrProperty.isIllegalFakeOverride(): Boolean { + if (!isFakeOverride) return false + val overriddenSymbols = overriddenSymbols + return overriddenSymbols.isEmpty() || overriddenSymbols.any { it.owner.isIllegalFakeOverride() } + } - fun findGetterOfProperty(propertySymbol: IrLocalDelegatedPropertySymbol): IrSimpleFunctionSymbol { - return getterForPropertyCache.getValue(propertySymbol) - } + if (fakeOverrideOwnerLookupTag != null && + firPropertySymbol is FirSyntheticPropertySymbol && + originalProperty.isIllegalFakeOverride() + ) { + // Fallback for a synthetic property complex case + return containingClassLookupTag.getIrCallableSymbol() + } - fun findSetterOfProperty(propertySymbol: IrLocalDelegatedPropertySymbol): IrSimpleFunctionSymbol? { - return setterForPropertyCache[propertySymbol] - } - - fun findDelegateVariableOfProperty(propertySymbol: IrLocalDelegatedPropertySymbol): IrVariableSymbol { - return delegateVariableForPropertyCache.getValue(propertySymbol) + return if (unmatchedOwner && fakeOverrideOwnerLookupTag is ConeClassLookupTagWithFixedSymbol) { + fakeOverrideOwnerLookupTag.findIrFakeOverride(fir.name, originalProperty) as IrPropertySymbol + } else { + originalSymbol + } } fun getCachedIrProperty(property: FirProperty): IrProperty? { @@ -655,53 +579,20 @@ class Fir2IrDeclarationStorage( } } - private inline fun getCachedIrCallable( - declaration: FC, - fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?, - cache: MutableMap, - signatureCalculator: () -> IdSignature?, - referenceIfAny: (IdSignature) -> IC? - ): IC? { - /* - * There should be two types of declarations: - * 1. Real declarations. They are stored in simple FirDeclaration -> IrDeclaration [cache] - * 2. Fake overrides. They are stored in [irFakeOverridesForRealFirFakeOverrideMap], where the key is the original real declaration and - * specific dispatch receiver of particular fake override. This cache is needed, because we can have two different FIR - * f/o for common and platform modules (because they are session dependent), but we should create IR declaration for them - * only once. So [irFakeOverridesForFirFakeOverrideMap] is shared between fir2ir conversion for different MPP modules - * (see KT-58229) - * - * Unfortunately, in the current implementation, there is a special case. - * If the fake override exists in FIR (i.e., it is an intersection or substitution override), and it comes from dependency module, - * corresponding LazyIrFunction or LazyIrProperty can be created, ignoring the fact that it is a fake override. - * In that case, it can sometimes be put to the wrong cache, as a normal declaration. - * - * To workaround this, we look up such declarations in both caches. - */ - val isFakeOverride = declaration.isFakeOverride(fakeOverrideOwnerLookupTag) - if (isFakeOverride) { - val key = FakeOverrideIdentifier( - declaration.unwrapFakeOverrides().symbol, - fakeOverrideOwnerLookupTag ?: declaration.containingClassLookupTag()!! - ) - irFakeOverridesForFirFakeOverrideMap[key]?.let { return it as IC } - } else { - cache[declaration]?.let { return it } - } + fun findGetterOfProperty(propertySymbol: IrPropertySymbol): IrSimpleFunctionSymbol? { + return getterForPropertyCache[propertySymbol] + } - // TODO: Special case mentioned above. Should be removed after fixing creation. KT-61085 - if (declaration.isSubstitutionOrIntersectionOverride) { - cache[declaration]?.let { return it } - } + fun findSetterOfProperty(propertySymbol: IrPropertySymbol): IrSimpleFunctionSymbol? { + return setterForPropertyCache[propertySymbol] + } - return signatureCalculator()?.let { signature -> - referenceIfAny(signature)?.let { irDeclaration -> - if (!isFakeOverride) { - cache[declaration] = irDeclaration - } - irDeclaration - } - } + fun findBackingFieldOfProperty(propertySymbol: IrPropertySymbol): IrFieldSymbol? { + return backingFieldForPropertyCache[propertySymbol] + } + + fun findPropertyForBackingField(fieldSymbol: IrFieldSymbol): IrPropertySymbol? { + return propertyForBackingFieldCache[fieldSymbol] } internal fun cacheDelegatedProperty(property: FirProperty, irProperty: IrProperty) { @@ -709,26 +600,76 @@ class Fir2IrDeclarationStorage( delegatedReverseCache[irProperty] = property } - internal fun saveFakeOverrideInClass( - irClass: IrClass, - originalDeclaration: FirCallableDeclaration, - fakeOverride: FirCallableDeclaration - ) { - fakeOverridesInClass.getOrPut(irClass, ::mutableMapOf)[originalDeclaration.asFakeOverrideKey()] = fakeOverride - } + // ------------------------------------ fields ------------------------------------ - fun getFakeOverrideInClass( - irClass: IrClass, - callableDeclaration: FirCallableDeclaration - ): FirCallableDeclaration? { - if (irClass is Fir2IrLazyClass) { - irClass.getFakeOverridesByName(callableDeclaration.symbol.callableId.callableName) + fun getIrFieldSymbol( + firFieldSymbol: FirFieldSymbol, + fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null + ): IrFieldSymbol { + val fir = firFieldSymbol.fir + val staticFakeOverrideKey = getFieldStaticFakeOverrideKey(fir, fakeOverrideOwnerLookupTag) + if (staticFakeOverrideKey == null) { + fieldCache[fir]?.let { return it.symbol } + } else { + generateLazyFakeOverrides(fir.name, fakeOverrideOwnerLookupTag) + // Lazy static fake override should always exist + return fieldStaticOverrideCache[staticFakeOverrideKey]!!.symbol } - val map = fakeOverridesInClass[irClass] - return map?.get(callableDeclaration.asFakeOverrideKey()) + // In case of type parameters from the parent as the field's return type, find the parent ahead to cache type parameters. + val irParent = findIrParent(fir) + + val unwrapped = fir.unwrapFakeOverrides() + if (unwrapped !== fir) { + return getIrFieldSymbol(unwrapped.symbol) + } + return createAndCacheIrField(fir, irParent).symbol } - fun getCachedIrDelegateOrBackingField(field: FirField): IrField? = fieldCache[field] + // TODO: there is a mess with methods for fields + // we have three (!) different functions to getOrCreate field in different circumstances + fun getOrCreateIrField(field: FirField, irParent: IrDeclarationParent?): IrField { + getCachedIrField(field, irParent)?.let { return it } + return createAndCacheIrField(field, irParent) + } + + private fun getCachedIrField(field: FirField, irParent: IrDeclarationParent?): IrField? { + val containingClassLookupTag = (irParent as IrClass?)?.classId?.toLookupTag() + val staticFakeOverrideKey = getFieldStaticFakeOverrideKey(field, containingClassLookupTag) + return if (staticFakeOverrideKey == null) { + fieldCache[field] + } else { + fieldStaticOverrideCache[staticFakeOverrideKey] + } + } + + fun getIrBackingFieldSymbol(firBackingFieldSymbol: FirBackingFieldSymbol): IrSymbol { + return getIrPropertyForwardedSymbol(firBackingFieldSymbol.fir.propertySymbol.fir) + } + + fun getIrDelegateFieldSymbol(firVariableSymbol: FirVariableSymbol<*>): IrSymbol { + return getIrPropertyForwardedSymbol(firVariableSymbol.fir) + } + + private fun getIrPropertyForwardedSymbol(fir: FirVariable): IrSymbol { + return when (fir) { + is FirProperty -> { + if (fir.isLocal) { + return localStorage.getDelegatedProperty(fir)?.delegate?.symbol ?: getIrVariableSymbol(fir) + } + propertyCache[fir]?.let { return it.backingField!!.symbol } + val irParent = findIrParent(fir) + val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED + createAndCacheIrProperty(fir, irParent, predefinedOrigin = parentOrigin).backingField!!.symbol + } + else -> { + getIrVariableSymbol(fir) + } + } + } + + fun getCachedIrDelegateOrBackingField(field: FirField): IrField? { + return fieldCache[field] + } fun getCachedIrFieldStaticFakeOverrideByDeclaration(field: FirField): IrField? { val ownerLookupTag = field.containingClassLookupTag() ?: return null @@ -785,32 +726,139 @@ class Fir2IrDeclarationStorage( return FieldStaticOverrideKey(ownerLookupTag, field.name) } - fun getIrConstructorSymbol(firConstructorSymbol: FirConstructorSymbol): IrConstructorSymbol { - val fir = firConstructorSymbol.fir - return getIrCallableSymbol( - firConstructorSymbol, - fakeOverrideOwnerLookupTag = null, - getCachedIrDeclaration = { constructor: FirConstructor, _, calculator -> getCachedIrConstructor(constructor, calculator) }, - createIrDeclaration = { parent, origin -> - callablesGenerator.createIrConstructor(fir, parent as IrClass, predefinedOrigin = origin) - }, - createIrLazyDeclaration = { signature, lazyParent, declarationOrigin -> - val symbol = Fir2IrConstructorSymbol(signature) - val irConstructor = fir.convertWithOffsets { startOffset, endOffset -> - symbolTable.declareConstructor(signature, { symbol }) { - Fir2IrLazyConstructor( - components, startOffset, endOffset, declarationOrigin, fir, symbol - ).apply { - parent = lazyParent - } - } - } - constructorCache[fir] = irConstructor - // NB: this is needed to prevent recursions in case of self bounds - (irConstructor as Fir2IrLazyConstructor).prepareTypeParameters() - irConstructor - }, - ) as IrConstructorSymbol + // ------------------------------------ parameters ------------------------------------ + + fun createAndCacheParameter( + valueParameter: FirValueParameter, + index: Int = UNDEFINED_PARAMETER_INDEX, + useStubForDefaultValueStub: Boolean = true, + typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT, + skipDefaultParameter: Boolean = false, + // Use this parameter if you want to insert the actual default value instead of the stub (overrides useStubForDefaultValueStub parameter). + // This parameter is intended to be used for default values of annotation parameters where they are needed and + // may produce incorrect results for values that may be encountered outside annotations. + // Does not do anything if valueParameter.defaultValue is already FirExpressionStub. + forcedDefaultValueConversion: Boolean = false, + ): IrValueParameter { + return callablesGenerator.createIrParameter( + valueParameter, + index, + useStubForDefaultValueStub, + typeOrigin, + skipDefaultParameter, + forcedDefaultValueConversion + ).also { + localStorage.putParameter(valueParameter, it) + } + } + + // ------------------------------------ local delegated properties ------------------------------------ + + fun findGetterOfProperty(propertySymbol: IrLocalDelegatedPropertySymbol): IrSimpleFunctionSymbol { + return getterForPropertyCache.getValue(propertySymbol) + } + + fun findSetterOfProperty(propertySymbol: IrLocalDelegatedPropertySymbol): IrSimpleFunctionSymbol? { + return setterForPropertyCache[propertySymbol] + } + + fun findDelegateVariableOfProperty(propertySymbol: IrLocalDelegatedPropertySymbol): IrVariableSymbol { + return delegateVariableForPropertyCache.getValue(propertySymbol) + } + + fun createAndCacheIrLocalDelegatedProperty( + property: FirProperty, + irParent: IrDeclarationParent + ): IrLocalDelegatedProperty { + val irProperty = callablesGenerator.createIrLocalDelegatedProperty(property, irParent) + val symbol = irProperty.symbol + delegateVariableForPropertyCache[symbol] = irProperty.delegate.symbol + getterForPropertyCache[symbol] = irProperty.getter.symbol + irProperty.setter?.let { setterForPropertyCache[symbol] = it.symbol } + localStorage.putDelegatedProperty(property, irProperty) + return irProperty + } + + // ------------------------------------ variables ------------------------------------ + + fun createAndCacheIrVariable( + variable: FirVariable, + irParent: IrDeclarationParent, + givenOrigin: IrDeclarationOrigin? = null + ): IrVariable { + return callablesGenerator.createIrVariable(variable, irParent, givenOrigin).also { + localStorage.putVariable(variable, it) + } + } + + fun getIrValueSymbol(firVariableSymbol: FirVariableSymbol<*>): IrSymbol { + return when (val firDeclaration = firVariableSymbol.fir) { + is FirEnumEntry -> { + classifierStorage.getCachedIrEnumEntry(firDeclaration)?.let { return it.symbol } + val irParentClass = firDeclaration.containingClassLookupTag()?.let { classifierStorage.findIrClass(it) } + + val firProviderForSymbol = firVariableSymbol.moduleData.session.firProvider + val containingFile = firProviderForSymbol.getFirCallableContainerFile(firVariableSymbol) + + classifierStorage.createIrEnumEntry( + firDeclaration, + irParent = irParentClass, + predefinedOrigin = if (containingFile != null) IrDeclarationOrigin.DEFINED else + irParentClass?.origin ?: IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB + ).symbol + } + is FirValueParameter -> { + localStorage.getParameter(firDeclaration)?.symbol + // catch parameter is FirValueParameter in FIR but IrVariable in IR + ?: return getIrVariableSymbol(firDeclaration) + } + else -> { + getIrVariableSymbol(firDeclaration) + } + } + } + + private fun getIrVariableSymbol(firVariable: FirVariable): IrVariableSymbol { + return localStorage.getVariable(firVariable)?.symbol + ?: run { + throw IllegalArgumentException("Cannot find variable ${firVariable.render()} in local storage") + } + } + + // ------------------------------------ anonymous initializers ------------------------------------ + + fun getOrCreateIrAnonymousInitializer( + anonymousInitializer: FirAnonymousInitializer, + containingIrClass: IrClass, + ): IrAnonymousInitializer { + return initializerCache.computeIfAbsent(anonymousInitializer) { + callablesGenerator.createIrAnonymousInitializer(anonymousInitializer, containingIrClass) + } + } + + // ------------------------------------ callables ------------------------------------ + + fun originalDeclarationForDelegated(irDeclaration: IrDeclaration): FirDeclaration? { + return delegatedReverseCache[irDeclaration] + } + + internal fun saveFakeOverrideInClass( + irClass: IrClass, + originalDeclaration: FirCallableDeclaration, + fakeOverride: FirCallableDeclaration + ) { + fakeOverridesInClass.getOrPut(irClass, ::mutableMapOf)[originalDeclaration.asFakeOverrideKey()] = fakeOverride + } + + fun getFakeOverrideInClass( + irClass: IrClass, + callableDeclaration: FirCallableDeclaration + ): FirCallableDeclaration? { + if (irClass is Fir2IrLazyClass) { + irClass.getFakeOverridesByName(callableDeclaration.symbol.callableId.callableName) + } + val map = fakeOverridesInClass[irClass] + return map?.get(callableDeclaration.asFakeOverrideKey()) } @OptIn(IrSymbolInternals::class) @@ -862,72 +910,53 @@ class Fir2IrDeclarationStorage( } } - - @OptIn(IrSymbolInternals::class) - fun getIrPropertySymbol( - firPropertySymbol: FirPropertySymbol, - fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null, - ): IrSymbol { - val fir = firPropertySymbol.fir - if (fir.isLocal) { - return localStorage.getDelegatedProperty(fir)?.symbol ?: getIrVariableSymbol(fir) - } - 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 originalSymbol = fakeOverrideOwnerLookupTag.getIrCallableSymbol() - val originalProperty = originalSymbol.owner as IrProperty - - fun IrProperty.isIllegalFakeOverride(): Boolean { - if (!isFakeOverride) return false - val overriddenSymbols = overriddenSymbols - 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 + private inline fun getCachedIrCallable( + declaration: FC, + fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?, + cache: MutableMap, + signatureCalculator: () -> IdSignature?, + referenceIfAny: (IdSignature) -> IC? + ): IC? { + /* + * There should be two types of declarations: + * 1. Real declarations. They are stored in simple FirDeclaration -> IrDeclaration [cache] + * 2. Fake overrides. They are stored in [irFakeOverridesForRealFirFakeOverrideMap], where the key is the original real declaration and + * specific dispatch receiver of particular fake override. This cache is needed, because we can have two different FIR + * f/o for common and platform modules (because they are session dependent), but we should create IR declaration for them + * only once. So [irFakeOverridesForFirFakeOverrideMap] is shared between fir2ir conversion for different MPP modules + * (see KT-58229) + * + * Unfortunately, in the current implementation, there is a special case. + * If the fake override exists in FIR (i.e., it is an intersection or substitution override), and it comes from dependency module, + * corresponding LazyIrFunction or LazyIrProperty can be created, ignoring the fact that it is a fake override. + * In that case, it can sometimes be put to the wrong cache, as a normal declaration. + * + * To workaround this, we look up such declarations in both caches. + */ + val isFakeOverride = declaration.isFakeOverride(fakeOverrideOwnerLookupTag) + if (isFakeOverride) { + val key = FakeOverrideIdentifier( + declaration.unwrapFakeOverrides().symbol, + fakeOverrideOwnerLookupTag ?: declaration.containingClassLookupTag()!! + ) + irFakeOverridesForFirFakeOverrideMap[key]?.let { return it as IC } } else { - originalSymbol + cache[declaration]?.let { return it } } - } + // TODO: Special case mentioned above. Should be removed after fixing creation. KT-61085 + if (declaration.isSubstitutionOrIntersectionOverride) { + cache[declaration]?.let { return it } + } - @OptIn(IrSymbolInternals::class) - private inline fun > ConeClassLookupTagWithFixedSymbol.findIrFakeOverride( - name: Name, originalDeclaration: IrOverridableDeclaration - ): IrSymbol? { - val dispatchReceiverIrClass = - classifierStorage.getIrClassSymbol(toSymbol(session) as FirClassSymbol).owner - return dispatchReceiverIrClass.declarations.find { - it is D && it.isFakeOverride && it.name == name && it.overrides(originalDeclaration) - }?.symbol + return signatureCalculator()?.let { signature -> + referenceIfAny(signature)?.let { irDeclaration -> + if (!isFakeOverride) { + cache[declaration] = irDeclaration + } + irDeclaration + } + } } @OptIn(IrSymbolInternals::class) @@ -1004,70 +1033,14 @@ class Fir2IrDeclarationStorage( } } - private fun computeDeclarationOrigin( - symbol: FirCallableSymbol<*>, - parentOrigin: IrDeclarationOrigin - ): IrDeclarationOrigin = when { - symbol.fir.isIntersectionOverride || symbol.fir.isSubstitutionOverride -> IrDeclarationOrigin.FAKE_OVERRIDE - parentOrigin == IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB && symbol.isJavaOrEnhancement -> { - IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB - } - symbol.origin is FirDeclarationOrigin.Plugin -> GeneratedByPlugin((symbol.origin as FirDeclarationOrigin.Plugin).key) - else -> parentOrigin + // ------------------------------------ scripts ------------------------------------ + + fun getCachedIrScript(script: FirScript): IrScript? { + return scriptCache[script] } - fun getIrFieldSymbol( - firFieldSymbol: FirFieldSymbol, - fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null - ): IrFieldSymbol { - val fir = firFieldSymbol.fir - val staticFakeOverrideKey = getFieldStaticFakeOverrideKey(fir, fakeOverrideOwnerLookupTag) - if (staticFakeOverrideKey == null) { - fieldCache[fir]?.let { return it.symbol } - } else { - generateLazyFakeOverrides(fir.name, fakeOverrideOwnerLookupTag) - // Lazy static fake override should always exist - return fieldStaticOverrideCache[staticFakeOverrideKey]!!.symbol - } - // In case of type parameters from the parent as the field's return type, find the parent ahead to cache type parameters. - val irParent = findIrParent(fir) - - val unwrapped = fir.unwrapFakeOverrides() - if (unwrapped !== fir) { - return getIrFieldSymbol(unwrapped.symbol) - } - return createAndCacheIrField(fir, irParent).symbol - } - - // TODO: there is a mess with methods for fields - // we have three (!) different functions to getOrCreate field in different circumstances - fun getOrCreateIrField(field: FirField, irParent: IrDeclarationParent?): IrField { - getCachedIrField(field, irParent)?.let { return it } - return createAndCacheIrField(field, irParent) - } - - private fun getCachedIrField(field: FirField, irParent: IrDeclarationParent?): IrField? { - val containingClassLookupTag = (irParent as IrClass?)?.classId?.toLookupTag() - val staticFakeOverrideKey = getFieldStaticFakeOverrideKey(field, containingClassLookupTag) - return if (staticFakeOverrideKey == null) { - fieldCache[field] - } else { - fieldStaticOverrideCache[staticFakeOverrideKey] - } - } - - fun getIrBackingFieldSymbol(firBackingFieldSymbol: FirBackingFieldSymbol): IrSymbol { - return getIrPropertyForwardedSymbol(firBackingFieldSymbol.fir.propertySymbol.fir) - } - - fun getIrDelegateFieldSymbol(firVariableSymbol: FirVariableSymbol<*>): IrSymbol { - return getIrPropertyForwardedSymbol(firVariableSymbol.fir) - } - - fun getCachedIrScript(script: FirScript): IrScript? = scriptCache[script] - - fun getOrCreateIrScript(script: FirScript): IrScript = - getCachedIrScript(script) ?: script.convertWithOffsets { startOffset, endOffset -> + fun getOrCreateIrScript(script: FirScript): IrScript { + return getCachedIrScript(script) ?: script.convertWithOffsets { startOffset, endOffset -> val signature = signatureComposer.composeSignature(script)!! symbolTable.declareScript(signature, { Fir2IrScriptSymbol(signature) }) { symbol -> IrScriptImpl(symbol, script.name, irFactory, startOffset, endOffset).also { irScript -> @@ -1080,107 +1053,168 @@ class Fir2IrDeclarationStorage( } } } + } + // ------------------------------------ scoping ------------------------------------ - private fun getIrPropertyForwardedSymbol(fir: FirVariable): IrSymbol { - return when (fir) { - is FirProperty -> { - if (fir.isLocal) { - return localStorage.getDelegatedProperty(fir)?.delegate?.symbol ?: getIrVariableSymbol(fir) + fun enterScope(symbol: IrSymbol) { + symbolTable.enterScope(symbol) + if (symbol is IrSimpleFunctionSymbol || + symbol is IrConstructorSymbol || + symbol is IrAnonymousInitializerSymbol || + symbol is IrPropertySymbol || + symbol is IrEnumEntrySymbol || + symbol is IrScriptSymbol + ) { + localStorage.enterCallable() + } + } + + fun leaveScope(symbol: IrSymbol) { + if (symbol is IrSimpleFunctionSymbol || + symbol is IrConstructorSymbol || + symbol is IrAnonymousInitializerSymbol || + symbol is IrPropertySymbol || + symbol is IrEnumEntrySymbol || + symbol is IrScriptSymbol + ) { + localStorage.leaveCallable() + } + symbolTable.leaveScope(symbol) + } + + inline fun withScope(symbol: IrSymbol, crossinline block: () -> Unit) { + enterScope(symbol) + block() + leaveScope(symbol) + } + + // ------------------------------------ utilities ------------------------------------ + + internal fun findIrParent( + packageFqName: FqName, + parentLookupTag: ConeClassLikeLookupTag?, + firBasedSymbol: FirBasedSymbol<*>, + firOrigin: FirDeclarationOrigin + ): IrDeclarationParent? { + if (parentLookupTag != null) { + return classifierStorage.findIrClass(parentLookupTag) + } + + val parentPackage = when (firBasedSymbol) { + is FirCallableSymbol<*> -> { + getIrExternalPackageFragment(packageFqName, firOrigin) + } + else -> { + // TODO: All classes from BUILT_INS_PACKAGE_FQ_NAMES are considered built-ins now, + // which is not exact and can lead to some problems + getIrExternalOrBuiltInsPackageFragment(packageFqName, firOrigin) + } + } + + val firProviderForSymbol = firBasedSymbol.moduleData.session.firProvider + val containerFile = when (firBasedSymbol) { + is FirCallableSymbol -> firProviderForSymbol.getFirCallableContainerFile(firBasedSymbol) + is FirClassLikeSymbol -> firProviderForSymbol.getFirClassifierContainerFileIfAny(firBasedSymbol) + else -> error("Unknown symbol: $firBasedSymbol") + } + + if (containerFile != null) { + val existingFile = fileCache[containerFile] + if (existingFile != null) { + return existingFile + } + + // Sudden declarations do not go through IR lowering process, + // so the parent file isn't replaced with a facade class, as in 'FileClassLowering'. + if (configuration.allowNonCachedDeclarations && firBasedSymbol is FirCallableSymbol<*>) { + val psiFile = containerFile.psi?.containingFile + if (psiFile is KtFile) { + val fileClassInfo = JvmFileClassUtil.getFileClassInfoNoResolve(psiFile) + val className = JvmClassName.byFqNameWithoutInnerClasses(fileClassInfo.fileClassFqName) + + val facadeClassName: JvmClassName? + val declarationOrigin: IrDeclarationOrigin + + if (fileClassInfo.withJvmMultifileClass) { + facadeClassName = JvmClassName.byFqNameWithoutInnerClasses(fileClassInfo.facadeClassFqName) + declarationOrigin = IrDeclarationOrigin.JVM_MULTIFILE_CLASS + } else { + facadeClassName = null + declarationOrigin = IrDeclarationOrigin.FILE_CLASS + } + + val facadeShortName = className.fqNameForClassNameWithoutDollars.shortName() + val containerSource = NonCachedSourceFacadeContainerSource(className, facadeClassName) + return NonCachedSourceFileFacadeClass(declarationOrigin, facadeShortName, containerSource).apply { + parent = parentPackage + createParameterDeclarations() + } } - propertyCache[fir]?.let { return it.backingField!!.symbol } - val irParent = findIrParent(fir) - val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED - createAndCacheIrProperty(fir, irParent, predefinedOrigin = parentOrigin).backingField!!.symbol - } - else -> { - getIrVariableSymbol(fir) } } + + return parentPackage } - private fun getIrVariableSymbol(firVariable: FirVariable): IrVariableSymbol { - return localStorage.getVariable(firVariable)?.symbol - ?: run { - throw IllegalArgumentException("Cannot find variable ${firVariable.render()} in local storage") - } + private fun findIrParent(callableDeclaration: FirCallableDeclaration): IrDeclarationParent? { + val firBasedSymbol = callableDeclaration.symbol + val callableId = firBasedSymbol.callableId + val callableOrigin = callableDeclaration.origin + return findIrParent(callableId.packageName, callableDeclaration.containingClassLookupTag(), firBasedSymbol, callableOrigin) } - fun getIrValueSymbol(firVariableSymbol: FirVariableSymbol<*>): IrSymbol { - return when (val firDeclaration = firVariableSymbol.fir) { - is FirEnumEntry -> { - classifierStorage.getCachedIrEnumEntry(firDeclaration)?.let { return it.symbol } - val irParentClass = firDeclaration.containingClassLookupTag()?.let { classifierStorage.findIrClass(it) } - - val firProviderForSymbol = firVariableSymbol.moduleData.session.firProvider - val containingFile = firProviderForSymbol.getFirCallableContainerFile(firVariableSymbol) - - classifierStorage.createIrEnumEntry( - firDeclaration, - irParent = irParentClass, - predefinedOrigin = if (containingFile != null) IrDeclarationOrigin.DEFINED else - irParentClass?.origin ?: IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB - ).symbol - } - is FirValueParameter -> { - localStorage.getParameter(firDeclaration)?.symbol - // catch parameter is FirValueParameter in FIR but IrVariable in IR - ?: return getIrVariableSymbol(firDeclaration) - } - else -> { - getIrVariableSymbol(firDeclaration) - } + @OptIn(IrSymbolInternals::class) + private fun areCompatible(firFunction: FirFunction, irFunction: IrFunction): Boolean { + if (firFunction is FirSimpleFunction && irFunction is IrSimpleFunction) { + if (irFunction.name != firFunction.name) return false } + return irFunction.valueParameters.size == firFunction.valueParameters.size && + irFunction.valueParameters.zip(firFunction.valueParameters).all { (irParameter, firParameter) -> + val irType = irParameter.type + val firType = firParameter.returnTypeRef.coneType + if (irType is IrSimpleType) { + when (val irClassifierSymbol = irType.classifier) { + is IrTypeParameterSymbol -> { + firType is ConeTypeParameterType + } + is IrClassSymbol -> { + val irClass = irClassifierSymbol.owner + firType is ConeClassLikeType && irClass.name == firType.lookupTag.name + } + is IrScriptSymbol -> { + false + } + } + } else { + false + } + } } - fun createAndCacheParameter( - valueParameter: FirValueParameter, - index: Int = UNDEFINED_PARAMETER_INDEX, - useStubForDefaultValueStub: Boolean = true, - typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT, - skipDefaultParameter: Boolean = false, - // Use this parameter if you want to insert the actual default value instead of the stub (overrides useStubForDefaultValueStub parameter). - // This parameter is intended to be used for default values of annotation parameters where they are needed and - // may produce incorrect results for values that may be encountered outside annotations. - // Does not do anything if valueParameter.defaultValue is already FirExpressionStub. - forcedDefaultValueConversion: Boolean = false, - ): IrValueParameter { - return callablesGenerator.createIrParameter( - valueParameter, - index, - useStubForDefaultValueStub, - typeOrigin, - skipDefaultParameter, - forcedDefaultValueConversion - ).also { - localStorage.putParameter(valueParameter, it) + @OptIn(IrSymbolInternals::class) + private inline fun > ConeClassLookupTagWithFixedSymbol.findIrFakeOverride( + name: Name, originalDeclaration: IrOverridableDeclaration + ): IrSymbol? { + val dispatchReceiverIrClass = + classifierStorage.getIrClassSymbol(toSymbol(session) as FirClassSymbol).owner + return dispatchReceiverIrClass.declarations.find { + it is D && it.isFakeOverride && it.name == name && it.overrides(originalDeclaration) + }?.symbol + } + + private fun computeDeclarationOrigin( + symbol: FirCallableSymbol<*>, + parentOrigin: IrDeclarationOrigin + ): IrDeclarationOrigin = when { + symbol.fir.isIntersectionOverride || symbol.fir.isSubstitutionOverride -> IrDeclarationOrigin.FAKE_OVERRIDE + parentOrigin == IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB && symbol.isJavaOrEnhancement -> { + IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB } + symbol.origin is FirDeclarationOrigin.Plugin -> GeneratedByPlugin((symbol.origin as FirDeclarationOrigin.Plugin).key) + else -> parentOrigin } - fun createAndCacheIrVariable( - variable: FirVariable, - irParent: IrDeclarationParent, - givenOrigin: IrDeclarationOrigin? = null - ): IrVariable { - return callablesGenerator.createIrVariable(variable, irParent, givenOrigin).also { - localStorage.putVariable(variable, it) - } - } - - fun createAndCacheIrLocalDelegatedProperty( - property: FirProperty, - irParent: IrDeclarationParent - ): IrLocalDelegatedProperty { - val irProperty = callablesGenerator.createIrLocalDelegatedProperty(property, irParent) - val symbol = irProperty.symbol - delegateVariableForPropertyCache[symbol] = irProperty.delegate.symbol - getterForPropertyCache[symbol] = irProperty.getter.symbol - irProperty.setter?.let { setterForPropertyCache[symbol] = it.symbol } - localStorage.putDelegatedProperty(property, irProperty) - return irProperty - } - - companion object { internal val ENUM_SYNTHETIC_NAMES = mapOf( Name.identifier("values") to IrSyntheticBodyKind.ENUM_VALUES, 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 dfdcaf42cf0..65b98a4d180 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 @@ -51,6 +51,8 @@ import org.jetbrains.kotlin.utils.addToStdlib.runUnless import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fir2IrComponents by components { + // ------------------------------------ package fragments ------------------------------------ + internal fun createExternalPackageFragment(fqName: FqName, moduleDescriptor: FirModuleDescriptor): IrExternalPackageFragment { return createExternalPackageFragment(FirPackageFragmentDescriptor(fqName, moduleDescriptor)) } @@ -60,205 +62,18 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi return IrExternalPackageFragmentImpl(symbol, packageFragmentDescriptor.fqName) } - /** - * [firCallable] is function or property (if [irFunction] is a property accessor) for - * which [irFunction] was build - * - * It is needed to determine proper dispatch receiver type if this declaration is fake-override - */ - private fun computeDispatchReceiverType( - irFunction: IrSimpleFunction, - firCallable: FirCallableDeclaration?, - parent: IrDeclarationParent?, - ): IrType? { - /* - * If some function is not fake-override, then its type should be just - * default type of containing class - * For fake overrides the default type calculated in the following way: - * 1. Find first overridden function, which is not fake override - * 2. Take its containing class - * 3. Find supertype of current containing class with type constructor of - * class from step 2 - */ - if (firCallable is FirProperty && firCallable.isLocal) return null - val containingClass = computeContainingClass(parent) ?: return null - val defaultType = containingClass.defaultType - if (firCallable == null) return defaultType - if (irFunction.origin != IrDeclarationOrigin.FAKE_OVERRIDE) return defaultType - - val originalCallable = firCallable.unwrapFakeOverrides() - val containerOfOriginalCallable = originalCallable.containingClassLookupTag() ?: return defaultType - val containerOfFakeOverride = firCallable.dispatchReceiverType ?: return defaultType - val correspondingSupertype = AbstractTypeChecker.findCorrespondingSupertypes( - session.typeContext.newTypeCheckerState(errorTypesEqualToAnything = false, stubTypesEqualToAnything = false), - containerOfFakeOverride, - containerOfOriginalCallable - ).firstOrNull() as ConeKotlinType? ?: return defaultType - return correspondingSupertype.toIrType() - } - - private fun computeContainingClass(parent: IrDeclarationParent?): IrClass? { - return if (parent is IrClass && parent !is Fir2IrDeclarationStorage.NonCachedSourceFileFacadeClass) { - parent - } else { - null - } - } - - fun setAndModifyParent(declaration: IrDeclaration, irParent: IrDeclarationParent?) { - if (irParent != null) { - declaration.parent = irParent - if (irParent is IrExternalPackageFragment) { - irParent.declarations += declaration - } - } - } - - private fun T.declareDefaultSetterParameter(type: IrType, firValueParameter: FirValueParameter?): T { - valueParameters = listOf( - createDefaultSetterParameter(startOffset, endOffset, type, parent = this, firValueParameter) - ) - return this - } - - internal fun createDefaultSetterParameter( - startOffset: Int, - endOffset: Int, - type: IrType, - parent: IrFunction, - firValueParameter: FirValueParameter?, - name: Name? = null, - isCrossinline: Boolean = false, - isNoinline: Boolean = false, - ): IrValueParameter { - return irFactory.createValueParameter( - startOffset = startOffset, - endOffset = endOffset, - origin = IrDeclarationOrigin.DEFINED, - name = name ?: SpecialNames.IMPLICIT_SET_PARAMETER, - type = type, - isAssignable = false, - symbol = IrValueParameterSymbolImpl(), - index = parent.contextReceiverParametersCount, - varargElementType = null, - isCrossinline = isCrossinline, - isNoinline = isNoinline, - isHidden = false, - ).apply { - this.parent = parent - if (firValueParameter != null) { - annotationGenerator.generate(this, firValueParameter) - } - } - } - - fun addContextReceiverParametersTo( - contextReceivers: List, - parent: IrFunction, - result: MutableList, - ) { - contextReceivers.mapIndexedTo(result) { index, contextReceiver -> - createIrParameterFromContextReceiver(contextReceiver, index).apply { - this.parent = parent - } - } - } - - /* - * In perfect world dispatchReceiverType should always be the default type of containing class - * But fake-overrides for members from Any have special rules for type of dispatch receiver - */ - private fun IrFunction.declareParameters( - function: FirFunction?, - irParent: IrDeclarationParent?, - dispatchReceiverType: IrType?, // has no sense for constructors - isStatic: Boolean, - forSetter: Boolean, - // Can be not-null only for property accessors - parentPropertyReceiver: FirReceiverParameter? = null - ) { - val containingClass = computeContainingClass(irParent) - val parent = this - if (function is FirSimpleFunction || function is FirConstructor) { - with(classifierStorage) { - setTypeParameters(function) - } - } - val typeOrigin = if (forSetter) ConversionTypeOrigin.SETTER else ConversionTypeOrigin.DEFAULT - if (function is FirDefaultPropertySetter) { - val valueParameter = function.valueParameters.first() - val type = valueParameter.returnTypeRef.toIrType(ConversionTypeOrigin.SETTER) - declareDefaultSetterParameter(type, valueParameter) - } else if (function != null) { - val contextReceivers = function.contextReceiversForFunctionOrContainingProperty() - - contextReceiverParametersCount = contextReceivers.size - valueParameters = buildList { - addContextReceiverParametersTo(contextReceivers, parent, this) - - function.valueParameters.mapIndexedTo(this) { index, valueParameter -> - declarationStorage.createAndCacheParameter( - valueParameter, index + contextReceiverParametersCount, - useStubForDefaultValueStub = function !is FirConstructor || containingClass?.name != Name.identifier("Enum"), - typeOrigin, - skipDefaultParameter = isFakeOverride || origin == IrDeclarationOrigin.DELEGATED_MEMBER - ).apply { - this.parent = parent - } - } - } - } - - val thisOrigin = IrDeclarationOrigin.DEFINED - if (function !is FirConstructor) { - val receiver: FirReceiverParameter? = - if (function !is FirPropertyAccessor && function != null) function.receiverParameter - else parentPropertyReceiver - if (receiver != null) { - extensionReceiverParameter = receiver.convertWithOffsets { startOffset, endOffset -> - val name = (function as? FirAnonymousFunction)?.label?.name?.let { - val suffix = it.takeIf(Name::isValidIdentifier) ?: "\$receiver" - Name.identifier("\$this\$$suffix") - } ?: SpecialNames.THIS - declareThisReceiverParameter( - thisType = receiver.typeRef.toIrType(typeOrigin), - thisOrigin = thisOrigin, - startOffset = startOffset, - endOffset = endOffset, - name = name, - explicitReceiver = receiver, - ) - } - } - // See [LocalDeclarationsLowering]: "local function must not have dispatch receiver." - val isLocal = function is FirSimpleFunction && function.isLocal - if (function !is FirAnonymousFunction && dispatchReceiverType != null && !isStatic && !isLocal) { - dispatchReceiverParameter = declareThisReceiverParameter( - thisType = dispatchReceiverType, - thisOrigin = thisOrigin - ) - } - } else { - // Set dispatch receiver parameter for inner class's constructor. - val outerClass = containingClass?.parentClassOrNull - if (containingClass?.isInner == true && outerClass != null) { - dispatchReceiverParameter = declareThisReceiverParameter( - thisType = outerClass.thisReceiver!!.type, - thisOrigin = thisOrigin - ) - } - } - } + // ------------------------------------ functions ------------------------------------ internal fun declareIrSimpleFunction( signature: IdSignature?, factory: (IrSimpleFunctionSymbol) -> IrSimpleFunction - ): IrSimpleFunction = - if (signature == null) { + ): IrSimpleFunction { + return if (signature == null) { factory(IrSimpleFunctionSymbolImpl()) } else { symbolTable.declareSimpleFunction(signature, { Fir2IrSimpleFunctionSymbol(signature) }, factory) } + } fun createIrFunction( function: FirFunction, @@ -355,28 +170,14 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi return created } - fun createIrAnonymousInitializer( - anonymousInitializer: FirAnonymousInitializer, - irParent: IrClass - ): IrAnonymousInitializer = convertCatching(anonymousInitializer) { - return anonymousInitializer.convertWithOffsets { startOffset, endOffset -> - symbolTable.descriptorExtension.declareAnonymousInitializer( - startOffset, - endOffset, - IrDeclarationOrigin.DEFINED, - irParent.descriptor - ).apply { - this.parent = irParent - } - } - } + // ------------------------------------ constructors ------------------------------------ - private fun declareIrConstructor(signature: IdSignature?, factory: (IrConstructorSymbol) -> IrConstructor): IrConstructor = - if (signature == null) + private fun declareIrConstructor(signature: IdSignature?, factory: (IrConstructorSymbol) -> IrConstructor): IrConstructor { + return if (signature == null) factory(IrConstructorSymbolImpl()) else symbolTable.declareConstructor(signature, { Fir2IrConstructorSymbol(signature) }, factory) - + } fun createIrConstructor( constructor: FirConstructor, @@ -421,154 +222,17 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi } } - private fun declareIrAccessor( - signature: IdSignature?, - factory: (IrSimpleFunctionSymbol) -> IrSimpleFunction - ): IrSimpleFunction = - if (signature == null) - factory(IrSimpleFunctionSymbolImpl()) - else - symbolTable.declareSimpleFunction(signature, { Fir2IrSimpleFunctionSymbol(signature) }, factory) - - private fun createIrPropertyAccessor( - propertyAccessor: FirPropertyAccessor?, - property: FirProperty, - correspondingProperty: IrDeclarationWithName, - propertyType: IrType, - irParent: IrDeclarationParent?, - isSetter: Boolean, - origin: IrDeclarationOrigin, - startOffset: Int, - endOffset: Int, - dontUseSignature: Boolean = false, - fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null, - propertyAccessorForAnnotations: FirPropertyAccessor? = propertyAccessor, - ): IrSimpleFunction = convertCatching(propertyAccessor ?: property) { - val prefix = if (isSetter) "set" else "get" - val signature = - runUnless(dontUseSignature) { - signatureComposer.composeAccessorSignature(property, isSetter, fakeOverrideOwnerLookupTag) - } - val containerSource = (correspondingProperty as? IrProperty)?.containerSource - return declareIrAccessor( - signature - ) { symbol -> - val accessorReturnType = if (isSetter) irBuiltIns.unitType else propertyType - val visibility = propertyAccessor?.visibility?.let { - components.visibilityConverter.convertToDescriptorVisibility(it) - } - irFactory.createSimpleFunction( - startOffset = startOffset, - endOffset = endOffset, - origin = origin, - name = Name.special("<$prefix-${correspondingProperty.name}>"), - visibility = visibility ?: (correspondingProperty as IrDeclarationWithVisibility).visibility, - isInline = propertyAccessor?.isInline == true, - isExpect = false, - returnType = accessorReturnType, - modality = (correspondingProperty as? IrOverridableMember)?.modality ?: Modality.FINAL, - symbol = symbol, - isTailrec = false, - isSuspend = false, - isOperator = false, - isInfix = false, - isExternal = propertyAccessor?.isExternal == true, - containerSource = containerSource, - ).apply { - correspondingPropertySymbol = (correspondingProperty as? IrProperty)?.symbol - if (propertyAccessor != null) { - metadata = FirMetadataSource.Function(propertyAccessor) - // Note that deserialized annotations are stored in the accessor, not the property. - convertAnnotationsForNonDeclaredMembers(propertyAccessor, origin) - } - - if (propertyAccessorForAnnotations != null) { - convertAnnotationsForNonDeclaredMembers(propertyAccessorForAnnotations, origin) - } - with(classifierStorage) { - setTypeParameters( - property, if (isSetter) ConversionTypeOrigin.SETTER else ConversionTypeOrigin.DEFAULT - ) - } - val dispatchReceiverType = computeDispatchReceiverType(this, property, irParent) - // NB: we should enter accessor' scope before declaring its parameters - // (both setter default and receiver ones, if any) - declarationStorage.withScope(symbol) { - if (propertyAccessor == null && isSetter) { - declareDefaultSetterParameter( - property.returnTypeRef.toIrType(ConversionTypeOrigin.SETTER), - firValueParameter = null - ) - } - setAndModifyParent(this, irParent) - declareParameters( - propertyAccessor, irParent, dispatchReceiverType, - isStatic = irParent !is IrClass || propertyAccessor?.isStatic == true, forSetter = isSetter, - parentPropertyReceiver = property.receiverParameter, - ) - } - if (correspondingProperty is Fir2IrLazyProperty && correspondingProperty.containingClass != null && !isFakeOverride && dispatchReceiverType != null) { - this.overriddenSymbols = correspondingProperty.fir.generateOverriddenAccessorSymbols( - correspondingProperty.containingClass, !isSetter - ) - } - } - } - } - - internal fun createBackingField( - irProperty: IrProperty, - firProperty: FirProperty, - origin: IrDeclarationOrigin, - visibility: DescriptorVisibility, - name: Name, - isFinal: Boolean, - firInitializerExpression: FirExpression?, - type: IrType? = null - ): IrField = convertCatching(firProperty) { - val inferredType = type ?: firInitializerExpression!!.resolvedType.toIrType() - return declareIrField { symbol -> - irFactory.createField( - startOffset = irProperty.startOffset, - endOffset = irProperty.endOffset, - origin = origin, - name = name, - visibility = visibility, - symbol = symbol, - type = inferredType, - isFinal = isFinal, - isStatic = firProperty.isStatic || !(irProperty.parent is IrClass || irProperty.parent is IrScript), - isExternal = firProperty.isExternal, - ).also { - it.correspondingPropertySymbol = irProperty.symbol - }.apply { - metadata = FirMetadataSource.Property(firProperty) - convertAnnotationsForNonDeclaredMembers(firProperty, origin) - } - } - } - - private val FirProperty.fieldVisibility: Visibility - get() = when { - hasExplicitBackingField -> backingField?.visibility ?: status.visibility - isLateInit -> setter?.visibility ?: status.visibility - isConst -> status.visibility - hasJvmFieldAnnotation(session) -> status.visibility - origin == FirDeclarationOrigin.ScriptCustomization.ResultProperty -> status.visibility - else -> Visibilities.Private - } + // ------------------------------------ properties ------------------------------------ private fun declareIrProperty( signature: IdSignature?, factory: (IrPropertySymbol) -> IrProperty - ): IrProperty = - if (signature == null) + ): IrProperty { + return if (signature == null) factory(IrPropertySymbolImpl()) else symbolTable.declareProperty(signature, { Fir2IrPropertySymbol(signature) }, factory) - - private fun declareIrField(factory: (IrFieldSymbol) -> IrField): IrField = - factory(IrFieldSymbolImpl()) + } fun createIrProperty( property: FirProperty, @@ -719,6 +383,152 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi return initializer } + // ------------------------------------ property accessors ------------------------------------ + + private fun declareIrAccessor( + signature: IdSignature?, + factory: (IrSimpleFunctionSymbol) -> IrSimpleFunction + ): IrSimpleFunction { + return if (signature == null) + factory(IrSimpleFunctionSymbolImpl()) + else + symbolTable.declareSimpleFunction(signature, { Fir2IrSimpleFunctionSymbol(signature) }, factory) + } + + private fun createIrPropertyAccessor( + propertyAccessor: FirPropertyAccessor?, + property: FirProperty, + correspondingProperty: IrDeclarationWithName, + propertyType: IrType, + irParent: IrDeclarationParent?, + isSetter: Boolean, + origin: IrDeclarationOrigin, + startOffset: Int, + endOffset: Int, + dontUseSignature: Boolean = false, + fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null, + propertyAccessorForAnnotations: FirPropertyAccessor? = propertyAccessor, + ): IrSimpleFunction = convertCatching(propertyAccessor ?: property) { + val prefix = if (isSetter) "set" else "get" + val signature = + runUnless(dontUseSignature) { + signatureComposer.composeAccessorSignature(property, isSetter, fakeOverrideOwnerLookupTag) + } + val containerSource = (correspondingProperty as? IrProperty)?.containerSource + return declareIrAccessor( + signature + ) { symbol -> + val accessorReturnType = if (isSetter) irBuiltIns.unitType else propertyType + val visibility = propertyAccessor?.visibility?.let { + components.visibilityConverter.convertToDescriptorVisibility(it) + } + irFactory.createSimpleFunction( + startOffset = startOffset, + endOffset = endOffset, + origin = origin, + name = Name.special("<$prefix-${correspondingProperty.name}>"), + visibility = visibility ?: (correspondingProperty as IrDeclarationWithVisibility).visibility, + isInline = propertyAccessor?.isInline == true, + isExpect = false, + returnType = accessorReturnType, + modality = (correspondingProperty as? IrOverridableMember)?.modality ?: Modality.FINAL, + symbol = symbol, + isTailrec = false, + isSuspend = false, + isOperator = false, + isInfix = false, + isExternal = propertyAccessor?.isExternal == true, + containerSource = containerSource, + ).apply { + correspondingPropertySymbol = (correspondingProperty as? IrProperty)?.symbol + if (propertyAccessor != null) { + metadata = FirMetadataSource.Function(propertyAccessor) + // Note that deserialized annotations are stored in the accessor, not the property. + convertAnnotationsForNonDeclaredMembers(propertyAccessor, origin) + } + + if (propertyAccessorForAnnotations != null) { + convertAnnotationsForNonDeclaredMembers(propertyAccessorForAnnotations, origin) + } + with(classifierStorage) { + setTypeParameters( + property, if (isSetter) ConversionTypeOrigin.SETTER else ConversionTypeOrigin.DEFAULT + ) + } + val dispatchReceiverType = computeDispatchReceiverType(this, property, irParent) + // NB: we should enter accessor' scope before declaring its parameters + // (both setter default and receiver ones, if any) + declarationStorage.withScope(symbol) { + if (propertyAccessor == null && isSetter) { + declareDefaultSetterParameter( + property.returnTypeRef.toIrType(ConversionTypeOrigin.SETTER), + firValueParameter = null + ) + } + setAndModifyParent(this, irParent) + declareParameters( + propertyAccessor, irParent, dispatchReceiverType, + isStatic = irParent !is IrClass || propertyAccessor?.isStatic == true, forSetter = isSetter, + parentPropertyReceiver = property.receiverParameter, + ) + } + if (correspondingProperty is Fir2IrLazyProperty && correspondingProperty.containingClass != null && !isFakeOverride && dispatchReceiverType != null) { + this.overriddenSymbols = correspondingProperty.fir.generateOverriddenAccessorSymbols( + correspondingProperty.containingClass, !isSetter + ) + } + } + } + } + + // ------------------------------------ fields ------------------------------------ + + internal fun createBackingField( + irProperty: IrProperty, + firProperty: FirProperty, + origin: IrDeclarationOrigin, + visibility: DescriptorVisibility, + name: Name, + isFinal: Boolean, + firInitializerExpression: FirExpression?, + type: IrType? = null + ): IrField = convertCatching(firProperty) { + val inferredType = type ?: firInitializerExpression!!.resolvedType.toIrType() + return declareIrField { symbol -> + irFactory.createField( + startOffset = irProperty.startOffset, + endOffset = irProperty.endOffset, + origin = origin, + name = name, + visibility = visibility, + symbol = symbol, + type = inferredType, + isFinal = isFinal, + isStatic = firProperty.isStatic || !(irProperty.parent is IrClass || irProperty.parent is IrScript), + isExternal = firProperty.isExternal, + ).also { + it.correspondingPropertySymbol = irProperty.symbol + }.apply { + metadata = FirMetadataSource.Property(firProperty) + convertAnnotationsForNonDeclaredMembers(firProperty, origin) + } + } + } + + private val FirProperty.fieldVisibility: Visibility + get() = when { + hasExplicitBackingField -> backingField?.visibility ?: status.visibility + isLateInit -> setter?.visibility ?: status.visibility + isConst -> status.visibility + hasJvmFieldAnnotation(session) -> status.visibility + origin == FirDeclarationOrigin.ScriptCustomization.ResultProperty -> status.visibility + else -> Visibilities.Private + } + + private fun declareIrField(factory: (IrFieldSymbol) -> IrField): IrField { + return factory(IrFieldSymbolImpl()) + } + fun createIrFieldAndDelegatedMembers(field: FirField, owner: FirClass, irClass: IrClass): IrField? { // Either take a corresponding constructor property backing field, // or create a separate delegate field @@ -783,6 +593,167 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi } } + // ------------------------------------ parameters ------------------------------------ + + private fun T.declareDefaultSetterParameter(type: IrType, firValueParameter: FirValueParameter?): T { + valueParameters = listOf( + createDefaultSetterParameter(startOffset, endOffset, type, parent = this, firValueParameter) + ) + return this + } + + internal fun createDefaultSetterParameter( + startOffset: Int, + endOffset: Int, + type: IrType, + parent: IrFunction, + firValueParameter: FirValueParameter?, + name: Name? = null, + isCrossinline: Boolean = false, + isNoinline: Boolean = false, + ): IrValueParameter { + return irFactory.createValueParameter( + startOffset = startOffset, + endOffset = endOffset, + origin = IrDeclarationOrigin.DEFINED, + name = name ?: SpecialNames.IMPLICIT_SET_PARAMETER, + type = type, + isAssignable = false, + symbol = IrValueParameterSymbolImpl(), + index = parent.contextReceiverParametersCount, + varargElementType = null, + isCrossinline = isCrossinline, + isNoinline = isNoinline, + isHidden = false, + ).apply { + this.parent = parent + if (firValueParameter != null) { + annotationGenerator.generate(this, firValueParameter) + } + } + } + + fun addContextReceiverParametersTo( + contextReceivers: List, + parent: IrFunction, + result: MutableList, + ) { + contextReceivers.mapIndexedTo(result) { index, contextReceiver -> + createIrParameterFromContextReceiver(contextReceiver, index).apply { + this.parent = parent + } + } + } + + private fun createIrParameterFromContextReceiver( + contextReceiver: FirContextReceiver, + index: Int, + ): IrValueParameter = convertCatching(contextReceiver) { + val type = contextReceiver.typeRef.toIrType() + return contextReceiver.convertWithOffsets { startOffset, endOffset -> + irFactory.createValueParameter( + startOffset = startOffset, + endOffset = endOffset, + origin = IrDeclarationOrigin.DEFINED, + name = NameUtils.contextReceiverName(index), + type = type, + isAssignable = false, + symbol = IrValueParameterSymbolImpl(), + index = index, + varargElementType = null, + isCrossinline = false, + isNoinline = false, + isHidden = false, + ) + } + } + + /* + * In perfect world dispatchReceiverType should always be the default type of containing class + * But fake-overrides for members from Any have special rules for type of dispatch receiver + */ + private fun IrFunction.declareParameters( + function: FirFunction?, + irParent: IrDeclarationParent?, + dispatchReceiverType: IrType?, // has no sense for constructors + isStatic: Boolean, + forSetter: Boolean, + // Can be not-null only for property accessors + parentPropertyReceiver: FirReceiverParameter? = null + ) { + val containingClass = computeContainingClass(irParent) + val parent = this + if (function is FirSimpleFunction || function is FirConstructor) { + with(classifierStorage) { + setTypeParameters(function) + } + } + val typeOrigin = if (forSetter) ConversionTypeOrigin.SETTER else ConversionTypeOrigin.DEFAULT + if (function is FirDefaultPropertySetter) { + val valueParameter = function.valueParameters.first() + val type = valueParameter.returnTypeRef.toIrType(ConversionTypeOrigin.SETTER) + declareDefaultSetterParameter(type, valueParameter) + } else if (function != null) { + val contextReceivers = function.contextReceiversForFunctionOrContainingProperty() + + contextReceiverParametersCount = contextReceivers.size + valueParameters = buildList { + addContextReceiverParametersTo(contextReceivers, parent, this) + + function.valueParameters.mapIndexedTo(this) { index, valueParameter -> + declarationStorage.createAndCacheParameter( + valueParameter, index + contextReceiverParametersCount, + useStubForDefaultValueStub = function !is FirConstructor || containingClass?.name != Name.identifier("Enum"), + typeOrigin, + skipDefaultParameter = isFakeOverride || origin == IrDeclarationOrigin.DELEGATED_MEMBER + ).apply { + this.parent = parent + } + } + } + } + + val thisOrigin = IrDeclarationOrigin.DEFINED + if (function !is FirConstructor) { + val receiver: FirReceiverParameter? = + if (function !is FirPropertyAccessor && function != null) function.receiverParameter + else parentPropertyReceiver + if (receiver != null) { + extensionReceiverParameter = receiver.convertWithOffsets { startOffset, endOffset -> + val name = (function as? FirAnonymousFunction)?.label?.name?.let { + val suffix = it.takeIf(Name::isValidIdentifier) ?: "\$receiver" + Name.identifier("\$this\$$suffix") + } ?: SpecialNames.THIS + declareThisReceiverParameter( + thisType = receiver.typeRef.toIrType(typeOrigin), + thisOrigin = thisOrigin, + startOffset = startOffset, + endOffset = endOffset, + name = name, + explicitReceiver = receiver, + ) + } + } + // See [LocalDeclarationsLowering]: "local function must not have dispatch receiver." + val isLocal = function is FirSimpleFunction && function.isLocal + if (function !is FirAnonymousFunction && dispatchReceiverType != null && !isStatic && !isLocal) { + dispatchReceiverParameter = declareThisReceiverParameter( + thisType = dispatchReceiverType, + thisOrigin = thisOrigin + ) + } + } else { + // Set dispatch receiver parameter for inner class's constructor. + val outerClass = containingClass?.parentClassOrNull + if (containingClass?.isInner == true && outerClass != null) { + dispatchReceiverParameter = declareThisReceiverParameter( + thisType = outerClass.thisReceiver!!.type, + thisOrigin = thisOrigin + ) + } + } + } + internal fun createIrParameter( valueParameter: FirValueParameter, index: Int = UNDEFINED_PARAMETER_INDEX, @@ -833,71 +804,7 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi return irParameter } - private fun createIrParameterFromContextReceiver( - contextReceiver: FirContextReceiver, - index: Int, - ): IrValueParameter = convertCatching(contextReceiver) { - val type = contextReceiver.typeRef.toIrType() - return contextReceiver.convertWithOffsets { startOffset, endOffset -> - irFactory.createValueParameter( - startOffset = startOffset, - endOffset = endOffset, - origin = IrDeclarationOrigin.DEFINED, - name = NameUtils.contextReceiverName(index), - type = type, - isAssignable = false, - symbol = IrValueParameterSymbolImpl(), - index = index, - varargElementType = null, - isCrossinline = false, - isNoinline = false, - isHidden = false, - ) - } - } - - // TODO: KT-58686 - private var lastTemporaryIndex: Int = 0 - private fun nextTemporaryIndex(): Int = lastTemporaryIndex++ - - private fun getNameForTemporary(nameHint: String?): String { - val index = nextTemporaryIndex() - return if (nameHint != null) "tmp${index}_$nameHint" else "tmp$index" - } - - private fun declareIrVariable( - startOffset: Int, endOffset: Int, - origin: IrDeclarationOrigin, name: Name, type: IrType, - isVar: Boolean, isConst: Boolean, isLateinit: Boolean - ): IrVariable = - IrVariableImpl( - startOffset, endOffset, origin, IrVariableSymbolImpl(), name, type, - isVar, isConst, isLateinit - ) - - fun createIrVariable( - variable: FirVariable, - irParent: IrDeclarationParent, - givenOrigin: IrDeclarationOrigin? - ): IrVariable = convertCatching(variable) { - val type = variable.irTypeForPotentiallyComponentCall() - // Some temporary variables are produced in RawFirBuilder, but we consistently use special names for them. - val origin = when { - givenOrigin != null -> givenOrigin - variable.name == SpecialNames.ITERATOR -> IrDeclarationOrigin.FOR_LOOP_ITERATOR - variable.name.isSpecial -> IrDeclarationOrigin.IR_TEMPORARY_VARIABLE - else -> IrDeclarationOrigin.DEFINED - } - val isLateInit = if (variable is FirProperty) variable.isLateInit else false - val irVariable = variable.convertWithOffsets { startOffset, endOffset -> - declareIrVariable( - startOffset, endOffset, origin, - variable.name, type, variable.isVar, isConst = false, isLateinit = isLateInit - ) - } - irVariable.parent = irParent - return irVariable - } + // ------------------------------------ local delegated properties ------------------------------------ fun createIrLocalDelegatedProperty( property: FirProperty, @@ -942,6 +849,17 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi return irProperty } + // ------------------------------------ variables ------------------------------------ + + // TODO: KT-58686 + private var lastTemporaryIndex: Int = 0 + private fun nextTemporaryIndex(): Int = lastTemporaryIndex++ + + private fun getNameForTemporary(nameHint: String?): String { + val index = nextTemporaryIndex() + return if (nameHint != null) "tmp${index}_$nameHint" else "tmp$index" + } + fun declareTemporaryVariable(base: IrExpression, nameHint: String? = null): IrVariable { return declareIrVariable( base.startOffset, base.endOffset, IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, @@ -952,6 +870,116 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi } } + fun createIrVariable( + variable: FirVariable, + irParent: IrDeclarationParent, + givenOrigin: IrDeclarationOrigin? + ): IrVariable = convertCatching(variable) { + val type = variable.irTypeForPotentiallyComponentCall() + // Some temporary variables are produced in RawFirBuilder, but we consistently use special names for them. + val origin = when { + givenOrigin != null -> givenOrigin + variable.name == SpecialNames.ITERATOR -> IrDeclarationOrigin.FOR_LOOP_ITERATOR + variable.name.isSpecial -> IrDeclarationOrigin.IR_TEMPORARY_VARIABLE + else -> IrDeclarationOrigin.DEFINED + } + val isLateInit = if (variable is FirProperty) variable.isLateInit else false + val irVariable = variable.convertWithOffsets { startOffset, endOffset -> + declareIrVariable( + startOffset, endOffset, origin, + variable.name, type, variable.isVar, isConst = false, isLateinit = isLateInit + ) + } + irVariable.parent = irParent + return irVariable + } + + private fun declareIrVariable( + startOffset: Int, endOffset: Int, + origin: IrDeclarationOrigin, name: Name, type: IrType, + isVar: Boolean, isConst: Boolean, isLateinit: Boolean + ): IrVariable { + return IrVariableImpl( + startOffset, endOffset, origin, IrVariableSymbolImpl(), name, type, + isVar, isConst, isLateinit + ) + } + + // ------------------------------------ anonymous initializers ------------------------------------ + + fun createIrAnonymousInitializer( + anonymousInitializer: FirAnonymousInitializer, + irParent: IrClass + ): IrAnonymousInitializer = convertCatching(anonymousInitializer) { + return anonymousInitializer.convertWithOffsets { startOffset, endOffset -> + symbolTable.descriptorExtension.declareAnonymousInitializer( + startOffset, + endOffset, + IrDeclarationOrigin.DEFINED, + irParent.descriptor + ).apply { + this.parent = irParent + } + } + } + + // ------------------------------------ scripts ------------------------------------ + // ------------------------------------ utilities ------------------------------------ + + /** + * [firCallable] is function or property (if [irFunction] is a property accessor) for + * which [irFunction] was build + * + * It is needed to determine proper dispatch receiver type if this declaration is fake-override + */ + private fun computeDispatchReceiverType( + irFunction: IrSimpleFunction, + firCallable: FirCallableDeclaration?, + parent: IrDeclarationParent?, + ): IrType? { + /* + * If some function is not fake-override, then its type should be just + * default type of containing class + * For fake overrides the default type calculated in the following way: + * 1. Find first overridden function, which is not fake override + * 2. Take its containing class + * 3. Find supertype of current containing class with type constructor of + * class from step 2 + */ + if (firCallable is FirProperty && firCallable.isLocal) return null + val containingClass = computeContainingClass(parent) ?: return null + val defaultType = containingClass.defaultType + if (firCallable == null) return defaultType + if (irFunction.origin != IrDeclarationOrigin.FAKE_OVERRIDE) return defaultType + + val originalCallable = firCallable.unwrapFakeOverrides() + val containerOfOriginalCallable = originalCallable.containingClassLookupTag() ?: return defaultType + val containerOfFakeOverride = firCallable.dispatchReceiverType ?: return defaultType + val correspondingSupertype = AbstractTypeChecker.findCorrespondingSupertypes( + session.typeContext.newTypeCheckerState(errorTypesEqualToAnything = false, stubTypesEqualToAnything = false), + containerOfFakeOverride, + containerOfOriginalCallable + ).firstOrNull() as ConeKotlinType? ?: return defaultType + return correspondingSupertype.toIrType() + } + + private fun computeContainingClass(parent: IrDeclarationParent?): IrClass? { + return if (parent is IrClass && parent !is Fir2IrDeclarationStorage.NonCachedSourceFileFacadeClass) { + parent + } else { + null + } + } + + fun setAndModifyParent(declaration: IrDeclaration, irParent: IrDeclarationParent?) { + if (irParent != null) { + declaration.parent = irParent + if (irParent is IrExternalPackageFragment) { + irParent.declarations += declaration + } + } + } + private fun IrMutableAnnotationContainer.convertAnnotationsForNonDeclaredMembers( firAnnotationContainer: FirAnnotationContainer, origin: IrDeclarationOrigin, ) {