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, ) {