diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt index b10bbd56376..6c038aad414 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt @@ -11,8 +11,6 @@ import com.intellij.psi.tree.IElementType import org.jetbrains.kotlin.* import org.jetbrains.kotlin.backend.common.actualizer.IrActualizedResult import org.jetbrains.kotlin.builtins.StandardNames.DATA_CLASS_COMPONENT_PREFIX -import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.ValueClassRepresentation import org.jetbrains.kotlin.diagnostics.startOffsetSkippingComments import org.jetbrains.kotlin.fir.* @@ -32,7 +30,6 @@ import org.jetbrains.kotlin.fir.extensions.extensionService import org.jetbrains.kotlin.fir.extensions.generatedDeclarationsSymbolProvider import org.jetbrains.kotlin.fir.references.FirReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference -import org.jetbrains.kotlin.fir.references.FirThisReference import org.jetbrains.kotlin.fir.references.impl.FirPropertyFromParameterResolvedNamedReference import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol import org.jetbrains.kotlin.fir.resolve.* @@ -153,7 +150,7 @@ fun FirClassifierSymbol<*>.toSymbol( val coneClassLikeType = fir.expandedTypeRef.coneType as ConeClassLikeType coneClassLikeType.lookupTag.toSymbol(session) ?.toSymbol(typeOrigin, handleAnnotations) - ?: classifierStorage.getIrClassSymbolForNotFoundClass(coneClassLikeType.lookupTag) + ?: classifiersGenerator.createIrClassSymbolForNotFoundClass(coneClassLikeType.lookupTag) } is FirClassSymbol -> { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt index 8927ba89065..adb902a56bd 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt @@ -6,38 +6,26 @@ package org.jetbrains.kotlin.fir.backend import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.fir.containingClassForLocalAttr import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression -import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass -import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag import org.jetbrains.kotlin.fir.resolve.providers.firProvider -import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.resolve.providers.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag -import org.jetbrains.kotlin.fir.symbols.Fir2IrClassSymbol -import org.jetbrains.kotlin.fir.symbols.Fir2IrEnumEntrySymbol -import org.jetbrains.kotlin.fir.symbols.Fir2IrTypeAliasSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.fir.types.toLookupTag import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.impl.* import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl -import org.jetbrains.kotlin.ir.util.IdSignature -import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.StandardClassIds -import org.jetbrains.kotlin.utils.addToStdlib.runIf -import org.jetbrains.kotlin.utils.addToStdlib.runUnless class Fir2IrClassifierStorage( private val components: Fir2IrComponents, @@ -45,10 +33,6 @@ class Fir2IrClassifierStorage( ) : Fir2IrComponents by components { private val classCache: MutableMap = commonMemberStorage.classCache - private val localClassesCreatedOnTheFly: MutableMap = mutableMapOf() - - private var processMembersOfClassesOnTheFlyImmediately = false - private val typeAliasCache: MutableMap = mutableMapOf() private val typeParameterCache: MutableMap = commonMemberStorage.typeParameterCache @@ -76,7 +60,7 @@ class Fir2IrClassifierStorage( val firClass = classId.toSymbol(session)?.fir as FirRegularClass? ?: continue val irClass = irBuiltinSymbol.owner classCache[firClass] = irClass - processClassHeader(firClass, irClass) + classifiersGenerator.processClassHeader(firClass, irClass) declarationStorage.preCacheBuiltinClassMembers(firClass, irClass) } for ((primitiveClassId, primitiveArrayId) in StandardClassIds.primitiveArrayTypeByElementType) { @@ -85,59 +69,32 @@ class Fir2IrClassifierStorage( val irType = typeConverter.classIdToTypeMap[primitiveClassId] val irClass = irBuiltIns.primitiveArrayForType[irType]!!.owner classCache[firClass] = irClass - processClassHeader(firClass, irClass) + classifiersGenerator.processClassHeader(firClass, irClass) declarationStorage.preCacheBuiltinClassMembers(firClass, irClass) } } // Note: declareTypeParameters should be called before! - private fun IrClass.setThisReceiver(typeParameters: List) { - symbolTable.enterScope(this) - val typeArguments = typeParameters.map { - IrSimpleTypeImpl(getIrTypeParameterSymbol(it.symbol, ConversionTypeOrigin.DEFAULT), false, emptyList(), emptyList()) - } - thisReceiver = declareThisReceiverParameter( - thisType = IrSimpleTypeImpl(symbol, false, typeArguments, emptyList()), - thisOrigin = IrDeclarationOrigin.INSTANCE_RECEIVER - ) - symbolTable.leaveScope(this) - } internal fun preCacheTypeParameters(owner: FirTypeParameterRefsOwner, irOwnerSymbol: IrSymbol) { for ((index, typeParameter) in owner.typeParameters.withIndex()) { val original = typeParameter.symbol.fir getCachedIrTypeParameter(original) - ?: createIrTypeParameterWithoutBounds(original, index, irOwnerSymbol) + ?: classifiersGenerator.createIrTypeParameterWithoutBounds(original, index, irOwnerSymbol) if (owner is FirProperty && owner.isVar) { val context = ConversionTypeOrigin.SETTER getCachedIrTypeParameter(original, context) - ?: createIrTypeParameterWithoutBounds(original, index, irOwnerSymbol, context) + ?: classifiersGenerator.createIrTypeParameterWithoutBounds(original, index, irOwnerSymbol, context) } } } - internal fun IrTypeParametersContainer.setTypeParameters( + internal fun setTypeParameters( + irOwner: IrTypeParametersContainer, owner: FirTypeParameterRefsOwner, typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT ) { - typeParameters = owner.typeParameters.mapIndexedNotNull { index, typeParameter -> - if (typeParameter !is FirTypeParameter) return@mapIndexedNotNull null - getIrTypeParameter(typeParameter, index, symbol, typeOrigin).apply { - parent = this@setTypeParameters - if (superTypes.isEmpty()) { - superTypes = typeParameter.bounds.map { it.toIrType(typeOrigin) } - } - } - } - } - - private fun IrClass.declareTypeParameters(klass: FirClass) { - preCacheTypeParameters(klass, symbol) - setTypeParameters(klass) - if (klass is FirRegularClass) { - val fieldsForContextReceiversOfCurrentClass = getFieldsWithContextReceiversForClass(this, klass) - declarations.addAll(fieldsForContextReceiversOfCurrentClass) - } + classifiersGenerator.setTypeParameters(irOwner, owner, typeOrigin) } fun getFieldsWithContextReceiversForClass(irClass: IrClass, klass: FirClass): List { @@ -163,16 +120,6 @@ class Fir2IrClassifierStorage( } } - private fun IrClass.declareSupertypes(klass: FirClass) { - superTypes = klass.superTypeRefs.map { superTypeRef -> superTypeRef.toIrType() } - } - - private fun IrClass.declareValueClassRepresentation(klass: FirRegularClass) { - if (this !is Fir2IrLazyClass) { - valueClassRepresentation = computeValueClassRepresentation(klass) - } - } - fun getCachedIrClass(klass: FirClass): IrClass? { return if (klass is FirAnonymousObject || klass is FirRegularClass && klass.visibility == Visibilities.Local) { localStorage[klass] @@ -189,337 +136,34 @@ class Fir2IrClassifierStorage( return codeFragmentCache[codeFragment] } - private fun FirRegularClass.enumClassModality(): Modality { - return when { - declarations.any { it is FirCallableDeclaration && it.modality == Modality.ABSTRACT } -> { - Modality.ABSTRACT - } - declarations.none { - it is FirEnumEntry && isEnumEntryWhichRequiresSubclass(it) - } -> { - Modality.FINAL - } - hasAbstractMembersInScope() -> { - Modality.ABSTRACT - } - else -> { - Modality.OPEN - } - } - } - - private fun FirRegularClass.hasAbstractMembersInScope(): Boolean { - val scope = unsubstitutedScope() - val names = scope.getCallableNames() - var hasAbstract = false - for (name in names) { - scope.processFunctionsByName(name) { - if (it.isAbstract) { - hasAbstract = true - } - } - if (hasAbstract) return true - scope.processPropertiesByName(name) { - if (it.isAbstract) { - hasAbstract = true - } - } - if (hasAbstract) return true - } - return false - } - - // This function is called when we refer local class earlier than we reach its declaration - // This can happen e.g. when implicit return type has a local class constructor - private fun createLocalIrClassOnTheFly(klass: FirClass): IrClass { - // finding the parent class that actually contains the [klass] in the tree - it is the root one that should be created on the fly - val classOrLocalParent = generateSequence(klass) { c -> - (c as? FirRegularClass)?.containingClassForLocalAttr?.let { lookupTag -> - (session.firProvider.symbolProvider.getSymbolByLookupTag(lookupTag)?.fir as? FirClass)?.takeIf { - it.declarations.contains(c) - } - } - }.last() - val result = converter.processLocalClassAndNestedClassesOnTheFly(classOrLocalParent, temporaryParent) - // Note: usually member creation and f/o binding is delayed till non-local classes are processed in Fir2IrConverter - // If non-local classes are already created (this means we are in body translation) we do everything immediately - // The last variant is possible for local variables like 'val a = object : Any() { ... }' - if (processMembersOfClassesOnTheFlyImmediately) { - converter.processClassMembers(classOrLocalParent, result) - converter.bindFakeOverridesInClass(result) - } else { - localClassesCreatedOnTheFly[classOrLocalParent] = result - } - return if (classOrLocalParent === klass) result - else (getCachedIrClass(klass) - ?: error("Assuming that all nested classes of ${classOrLocalParent.classId.asString()} should already be cached")) - } - - // Note: this function is called exactly once, right after Fir2IrConverter finished f/o binding for regular classes - fun processMembersOfClassesCreatedOnTheFly() { - // After the call of this function, members of local classes may be processed immediately - // Before the call it's not possible, because f/o binding for regular classes isn't done yet - processMembersOfClassesOnTheFlyImmediately = true - for ((klass, irClass) in localClassesCreatedOnTheFly) { - converter.processClassMembers(klass, irClass) - // See the problem from KT-57441 -// class Wrapper { -// private val dummy = object: Bar {} -// private val bar = object: Bar by dummy {} -// } -// interface Bar { -// val foo: String -// get() = "" -// } - // When we are building bar.foo fake override, we should call dummy.foo, - // so we should have object : Bar.foo fake override to be built and bound. - converter.bindFakeOverridesInClass(irClass) - } - localClassesCreatedOnTheFly.clear() - } - - fun processClassHeader(klass: FirClass, irClass: IrClass = getCachedIrClass(klass)!!): IrClass { - irClass.declareTypeParameters(klass) - irClass.setThisReceiver(klass.typeParameters) - irClass.declareSupertypes(klass) - if (klass is FirRegularClass) { - irClass.declareValueClassRepresentation(klass) - } - return irClass - } - - private fun declareIrTypeAlias(signature: IdSignature?, factory: (IrTypeAliasSymbol) -> IrTypeAlias): IrTypeAlias = - if (signature == null) - factory(IrTypeAliasSymbolImpl()) - else - symbolTable.declareTypeAlias(signature, { Fir2IrTypeAliasSymbol(signature) }, factory) - - fun registerTypeAlias( + fun createAndCacheIrTypeAlias( typeAlias: FirTypeAlias, parent: IrDeclarationParent ): IrTypeAlias { - val signature = signatureComposer.composeSignature(typeAlias) - return typeAlias.convertWithOffsets { startOffset, endOffset -> - declareIrTypeAlias(signature) { symbol -> - preCacheTypeParameters(typeAlias, symbol) - val irTypeAlias = irFactory.createTypeAlias( - startOffset = startOffset, - endOffset = endOffset, - origin = IrDeclarationOrigin.DEFINED, - name = typeAlias.name, - visibility = components.visibilityConverter.convertToDescriptorVisibility(typeAlias.visibility), - symbol = symbol, - isActual = typeAlias.isActual, - expandedType = typeAlias.expandedTypeRef.toIrType(), - ).apply { - this.parent = parent - setTypeParameters(typeAlias) - if (parent is IrFile) { - parent.declarations += this - } - } - typeAliasCache[typeAlias] = irTypeAlias - irTypeAlias - } - } + return classifiersGenerator.createIrTypeAlias(typeAlias, parent) } internal fun getCachedTypeAlias(firTypeAlias: FirTypeAlias): IrTypeAlias? = typeAliasCache[firTypeAlias] - private fun declareIrClass(signature: IdSignature?, factory: (IrClassSymbol) -> IrClass): IrClass = - if (signature == null) - factory(IrClassSymbolImpl()) - else - symbolTable.declareClass(signature, { Fir2IrClassSymbol(signature) }, factory) - - fun registerIrClass( + fun createAndCacheIrClass( regularClass: FirRegularClass, parent: IrDeclarationParent, predefinedOrigin: IrDeclarationOrigin? = null ): IrClass { - val visibility = regularClass.visibility - val modality = when (regularClass.classKind) { - ClassKind.ENUM_CLASS -> regularClass.enumClassModality() - ClassKind.ANNOTATION_CLASS -> Modality.OPEN - else -> regularClass.modality ?: Modality.FINAL - } - val signature = runUnless(regularClass.isLocal || !configuration.linkViaSignatures) { - signatureComposer.composeSignature(regularClass) - } - val irClass = regularClass.convertWithOffsets { startOffset, endOffset -> - declareIrClass(signature) { symbol -> - irFactory.createClass( - startOffset = startOffset, - endOffset = endOffset, - origin = regularClass.computeIrOrigin(predefinedOrigin), - name = regularClass.name, - visibility = components.visibilityConverter.convertToDescriptorVisibility(visibility), - symbol = symbol, - kind = regularClass.classKind, - modality = modality, - isExternal = regularClass.isExternal, - isCompanion = regularClass.isCompanion, - isInner = regularClass.isInner, - isData = regularClass.isData, - isValue = regularClass.isInline, - isExpect = regularClass.isExpect, - isFun = regularClass.isFun - ).apply { - metadata = FirMetadataSource.Class(regularClass) - } - } - } - irClass.parent = parent - if (regularClass.visibility == Visibilities.Local) { - localStorage[regularClass] = irClass - } else { - classCache[regularClass] = irClass - } - return irClass + return classifiersGenerator.createIrClass(regularClass, parent, predefinedOrigin) } - fun registerIrAnonymousObject( + fun createAndCacheAnonymousObject( anonymousObject: FirAnonymousObject, visibility: Visibility = Visibilities.Local, name: Name = SpecialNames.NO_NAME_PROVIDED, irParent: IrDeclarationParent? = null ): IrClass { - val origin = IrDeclarationOrigin.DEFINED - val modality = Modality.FINAL - val irAnonymousObject = anonymousObject.convertWithOffsets { startOffset, endOffset -> - irFactory.createClass( - startOffset = startOffset, - endOffset = endOffset, - origin = origin, - name = name, - visibility = components.visibilityConverter.convertToDescriptorVisibility(visibility), - symbol = IrClassSymbolImpl(), - kind = anonymousObject.classKind, - modality = modality, - ).apply { - metadata = FirMetadataSource.Class(anonymousObject) - } - } - if (irParent != null) { - irAnonymousObject.parent = irParent - } - localStorage[anonymousObject] = irAnonymousObject - return irAnonymousObject + return classifiersGenerator.createAnonymousObject(anonymousObject, visibility, name, irParent) } - fun registerCodeFragmentClass(codeFragment: FirCodeFragment, containingFile: IrFile): IrClass { - val conversionData = codeFragment.conversionData - val signature = signatureComposer.composeSignature(codeFragment) - - val irClass = codeFragment.convertWithOffsets { startOffset, endOffset -> - declareIrClass(signature) { symbol -> - irFactory.createClass( - startOffset, - endOffset, - IrDeclarationOrigin.DEFINED, - conversionData.classId.shortClassName, - DescriptorVisibilities.PUBLIC, - symbol, - ClassKind.CLASS, - Modality.FINAL, - isExternal = false, - isCompanion = false, - isInner = false, - isData = false, - isValue = false, - isExpect = false, - isFun = false - ).apply { - metadata = FirMetadataSource.CodeFragment(codeFragment) - parent = containingFile - typeParameters = emptyList() - thisReceiver = declareThisReceiverParameter( - thisType = IrSimpleTypeImpl(symbol, false, emptyList(), emptyList()), - thisOrigin = IrDeclarationOrigin.INSTANCE_RECEIVER - ) - superTypes = listOf(irBuiltIns.anyType) - } - } - } - codeFragmentCache[codeFragment] = irClass - return irClass - } - - private fun getIrAnonymousObjectForEnumEntry(anonymousObject: FirAnonymousObject, name: Name, irParent: IrClass?): IrClass { - localStorage[anonymousObject]?.let { return it } - val irAnonymousObject = registerIrAnonymousObject(anonymousObject, Visibilities.Private, name, irParent) - processClassHeader(anonymousObject, irAnonymousObject) - return irAnonymousObject - } - - private fun createIrTypeParameterWithoutBounds( - typeParameter: FirTypeParameter, - index: Int, - ownerSymbol: IrSymbol, - typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT, - ): IrTypeParameter { - require(index >= 0) - val origin = typeParameter.computeIrOrigin() - val irTypeParameter = with(typeParameter) { - convertWithOffsets { startOffset, endOffset -> - signatureComposer.composeTypeParameterSignature( - index, ownerSymbol.signature - )?.let { signature -> - if (ownerSymbol is IrClassifierSymbol) { - symbolTable.declareGlobalTypeParameter( - signature, - symbolFactory = { IrTypeParameterPublicSymbolImpl(signature) } - ) { symbol -> - irFactory.createTypeParameter( - startOffset = startOffset, - endOffset = endOffset, - origin = origin, - name = name, - symbol = symbol, - variance = variance, - index = if (index < 0) 0 else index, - isReified = isReified, - ) - } - } else { - symbolTable.declareScopedTypeParameter( - signature, - symbolFactory = { IrTypeParameterPublicSymbolImpl(signature) } - ) { symbol -> - irFactory.createTypeParameter( - startOffset = startOffset, - endOffset = endOffset, - origin = origin, - name = name, - symbol = symbol, - variance = variance, - index = if (index < 0) 0 else index, - isReified = isReified, - ) - } - - } - } ?: irFactory.createTypeParameter( - startOffset = startOffset, - endOffset = endOffset, - origin = origin, - name = name, - symbol = IrTypeParameterSymbolImpl(), - variance = variance, - index = if (index < 0) 0 else index, - isReified = isReified, - ) - } - } - - // Cache the type parameter BEFORE processing its bounds/supertypes, to properly handle recursive type bounds. - if (typeOrigin.forSetter) { - typeParameterCacheForSetter[typeParameter] = irTypeParameter - } else { - typeParameterCache[typeParameter] = irTypeParameter - } - annotationGenerator.generate(irTypeParameter, typeParameter) - return irTypeParameter + fun createAndCacheCodeFragmentClass(codeFragment: FirCodeFragment, containingFile: IrFile): IrClass { + return classifiersGenerator.createCodeFragmentClass(codeFragment, containingFile) } internal fun getCachedIrTypeParameter( @@ -539,11 +183,7 @@ class Fir2IrClassifierStorage( typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT ): IrTypeParameter { getCachedIrTypeParameter(typeParameter, typeOrigin)?.let { return it } - return typeParameter.run { - val irTypeParameter = createIrTypeParameterWithoutBounds(typeParameter, index, ownerSymbol, typeOrigin) - irTypeParameter.superTypes = bounds.map { it.toIrType() } - irTypeParameter - } + return classifiersGenerator.createIrTypeParameterWithBounds(typeParameter, index, ownerSymbol, typeOrigin) } fun putEnumEntryClassInScope(enumEntry: FirEnumEntry, correspondingClass: IrClass) { @@ -552,12 +192,6 @@ class Fir2IrClassifierStorage( internal fun getCachedIrEnumEntry(enumEntry: FirEnumEntry): IrEnumEntry? = enumEntryCache[enumEntry] - private fun declareIrEnumEntry(signature: IdSignature?, factory: (IrEnumEntrySymbol) -> IrEnumEntry): IrEnumEntry = - if (signature == null) - factory(IrEnumEntrySymbolImpl()) - else - symbolTable.declareEnumEntry(signature, { Fir2IrEnumEntrySymbol(signature) }, factory) - fun getIrEnumEntry( enumEntry: FirEnumEntry, irParent: IrClass, @@ -574,7 +208,7 @@ class Fir2IrClassifierStorage( } else { irParent.origin } - return createIrEnumEntry( + return classifiersGenerator.createIrEnumEntry( enumEntry, irParent = irParent, predefinedOrigin = predefinedOrigin @@ -595,110 +229,8 @@ class Fir2IrClassifierStorage( } } - fun createIrEnumEntry( - enumEntry: FirEnumEntry, - irParent: IrClass?, - predefinedOrigin: IrDeclarationOrigin? = null, - ): IrEnumEntry { - return enumEntry.convertWithOffsets { startOffset, endOffset -> - val signature = signatureComposer.composeSignature(enumEntry) - val result = declareIrEnumEntry(signature) { symbol -> - val origin = enumEntry.computeIrOrigin(predefinedOrigin) - irFactory.createEnumEntry( - startOffset = startOffset, - endOffset = endOffset, - origin = origin, - name = enumEntry.name, - symbol = symbol, - ).apply { - declarationStorage.enterScope(this.symbol) - if (irParent != null) { - this.parent = irParent - } - if (isEnumEntryWhichRequiresSubclass(enumEntry)) { - // An enum entry with its own members requires an anonymous object generated. - // Otherwise, this is a default-ish enum entry whose initializer would be a delegating constructor call, - // which will be translated via visitor later. - val klass = getIrAnonymousObjectForEnumEntry( - (enumEntry.initializer as FirAnonymousObjectExpression).anonymousObject, enumEntry.name, irParent - ) - this.correspondingClass = klass - } - declarationStorage.leaveScope(this.symbol) - } - } - enumEntryCache[enumEntry] = result - result - } - } - - private fun isEnumEntryWhichRequiresSubclass(enumEntry: FirEnumEntry): Boolean { - val initializer = enumEntry.initializer - return initializer is FirAnonymousObjectExpression && initializer.anonymousObject.declarations.any { it !is FirConstructor } - } - fun getIrClassSymbol(firClassSymbol: FirClassSymbol<*>): IrClassSymbol { - val firClass = firClassSymbol.fir - getCachedIrClass(firClass)?.let { return it.symbol } - if (firClass is FirAnonymousObject || firClass is FirRegularClass && firClass.visibility == Visibilities.Local) { - return createLocalIrClassOnTheFly(firClass).symbol - } - firClass as FirRegularClass - val classId = firClassSymbol.classId - val parentId = classId.outerClassId - val parentClass = parentId?.let { session.symbolProvider.getClassLikeSymbolByClassId(it) } - val irParent = declarationStorage.findIrParent(classId.packageFqName, parentClass?.toLookupTag(), firClassSymbol, firClass.origin)!! - - // firClass may be referenced by some parent's type parameters as a bound. In that case, getIrClassSymbol will be called recursively. - getCachedIrClass(firClass)?.let { return it.symbol } - - val signature = runIf(configuration.linkViaSignatures) { - signatureComposer.composeSignature(firClass) - } - val irClass = firClass.convertWithOffsets { startOffset, endOffset -> - declareIrClass(signature) { irClassSymbol -> - val firClassOrigin = firClass.irOrigin(session.firProvider) - Fir2IrLazyClass(components, startOffset, endOffset, firClassOrigin, firClass, irClassSymbol).apply { - parent = irParent - } - } - } - classCache[firClass] = irClass - // NB: this is needed to prevent recursions in case of self bounds - (irClass as Fir2IrLazyClass).prepareTypeParameters() - - return irClass.symbol - } - - @OptIn(IrSymbolInternals::class) - fun getIrClassSymbolForNotFoundClass(classLikeLookupTag: ConeClassLikeLookupTag): IrClassSymbol { - val classId = classLikeLookupTag.classId - val signature = IdSignature.CommonSignature( - packageFqName = classId.packageFqName.asString(), - declarationFqName = classId.relativeClassName.asString(), - id = 0, - mask = 0, - description = null, - ) - - val parentId = classId.outerClassId - val parentClass = parentId?.let { getIrClassSymbolForNotFoundClass(it.toLookupTag()) } - val irParent = parentClass?.owner ?: declarationStorage.getIrExternalPackageFragment(classId.packageFqName) - - return symbolTable.referenceClass(signature, { Fir2IrClassSymbol(signature) }) { - irFactory.createClass( - startOffset = UNDEFINED_OFFSET, - endOffset = UNDEFINED_OFFSET, - origin = IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB, - name = classId.shortClassName, - visibility = DescriptorVisibilities.DEFAULT_VISIBILITY, - symbol = it, - kind = ClassKind.CLASS, - modality = Modality.FINAL, - ).apply { - parent = irParent - } - } + return classifiersGenerator.createIrClassSymbolByFirSymbol(firClassSymbol) } fun getIrTypeParameterSymbol( @@ -715,40 +247,9 @@ class Fir2IrClassifierStorage( } if (components.configuration.allowNonCachedDeclarations) { - val firTypeParameterOwnerSymbol = firTypeParameter.containingDeclarationSymbol - val firTypeParameterOwner = firTypeParameterOwnerSymbol.fir as FirTypeParameterRefsOwner - val index = firTypeParameterOwner.typeParameters.indexOf(firTypeParameter).also { check(it >= 0) } - - val isSetter = firTypeParameterOwner is FirPropertyAccessor && firTypeParameterOwner.isSetter - val conversionTypeOrigin = if (isSetter) ConversionTypeOrigin.SETTER else ConversionTypeOrigin.DEFAULT - - return createIrTypeParameterWithoutBounds(firTypeParameter, index, IrTypeParameterSymbolImpl(), conversionTypeOrigin).apply { - superTypes = firTypeParameter.bounds.map { it.toIrType(typeConverter) } - }.symbol + return classifiersGenerator.createIrTypeParameterForNonCachedDeclaration(firTypeParameter) } error("Cannot find cached type parameter by FIR symbol: ${firTypeParameterSymbol.name} of the owner: ${firTypeParameter.containingDeclarationSymbol}") } - - private val temporaryParent by lazy { - irFactory.createSimpleFunction( - startOffset = UNDEFINED_OFFSET, - endOffset = UNDEFINED_OFFSET, - origin = IrDeclarationOrigin.DEFINED, - name = Name.special(""), - visibility = DescriptorVisibilities.PRIVATE, - isInline = false, - isExpect = false, - returnType = irBuiltIns.unitType, - modality = Modality.FINAL, - symbol = IrSimpleFunctionSymbolImpl(), - isTailrec = false, - isSuspend = false, - isOperator = false, - isInfix = false, - isExternal = false, - ).apply { - parent = IrExternalPackageFragmentImpl(IrExternalPackageFragmentSymbolImpl(), FqName.ROOT) - } - } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponents.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponents.kt index 18ca4e31152..70745575504 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponents.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponents.kt @@ -35,6 +35,7 @@ interface Fir2IrComponents { val visibilityConverter: Fir2IrVisibilityConverter val callablesGenerator: Fir2IrCallableDeclarationsGenerator + val classifiersGenerator: Fir2IrClassifiersGenerator val lazyDeclarationsGenerator: Fir2IrLazyDeclarationsGenerator val annotationGenerator: AnnotationGenerator diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt index dc2c5601a7e..20343fb02a8 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt @@ -38,6 +38,7 @@ class Fir2IrComponentsStorage( override val declarationStorage: Fir2IrDeclarationStorage = Fir2IrDeclarationStorage(this, moduleDescriptor, commonMemberStorage) override val callablesGenerator: Fir2IrCallableDeclarationsGenerator = Fir2IrCallableDeclarationsGenerator(this) + override val classifiersGenerator: Fir2IrClassifiersGenerator = Fir2IrClassifiersGenerator(this) override val lazyDeclarationsGenerator: Fir2IrLazyDeclarationsGenerator = Fir2IrLazyDeclarationsGenerator(this) // builtins should go after storages and generators, because they use them during initialization diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt index cde88c26ea6..6b30989be84 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt @@ -92,7 +92,7 @@ class Fir2IrConverter( postponedDeclarationsForFakeOverridesBinding.clear() // Do (3) and (4) for local classes encountered during (3) - classifierStorage.processMembersOfClassesCreatedOnTheFly() + classifiersGenerator.processMembersOfClassesCreatedOnTheFly() // 5. Body processing // If we encounter local class / anonymous object here, then we perform all (1)-(5) stages immediately @@ -156,7 +156,7 @@ class Fir2IrConverter( for (declaration in file.declarations) { when (declaration) { is FirRegularClass -> registerClassAndNestedClasses(declaration, irFile) - is FirCodeFragment -> classifierStorage.registerCodeFragmentClass(declaration, irFile) + is FirCodeFragment -> classifierStorage.createAndCacheCodeFragmentClass(declaration, irFile) else -> {} } } @@ -167,7 +167,7 @@ class Fir2IrConverter( file.declarations.forEach { when (it) { is FirRegularClass -> processClassAndNestedClassHeaders(it) - is FirTypeAlias -> classifierStorage.registerTypeAlias(it, declarationStorage.getIrFile(file)) + is FirTypeAlias -> classifierStorage.createAndCacheIrTypeAlias(it, declarationStorage.getIrFile(file)) else -> {} } } @@ -373,8 +373,8 @@ class Fir2IrConverter( classifierStorage.getCachedIrClass(klass)?.apply { this.parent = parent } ?: when (klass) { - is FirRegularClass -> classifierStorage.registerIrClass(klass, parent) - is FirAnonymousObject -> classifierStorage.registerIrAnonymousObject(klass, irParent = parent) + is FirRegularClass -> classifierStorage.createAndCacheIrClass(klass, parent) + is FirAnonymousObject -> classifierStorage.createAndCacheAnonymousObject(klass, irParent = parent) } registerNestedClasses(klass, irClass) return irClass @@ -396,7 +396,7 @@ class Fir2IrConverter( } private fun processClassAndNestedClassHeaders(klass: FirClass) { - classifierStorage.processClassHeader(klass) + classifiersGenerator.processClassHeader(klass) processNestedClassHeaders(klass) } @@ -437,7 +437,7 @@ class Fir2IrConverter( registerClassAndNestedClasses(scriptStatement, irScript) processClassAndNestedClassHeaders(scriptStatement) } - is FirTypeAlias -> classifierStorage.registerTypeAlias(scriptStatement, irScript) + is FirTypeAlias -> classifierStorage.createAndCacheIrTypeAlias(scriptStatement, irScript) else -> {} } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt index 144b437ccaf..04ea6eab89b 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt @@ -124,7 +124,7 @@ class Fir2IrTypeConverter( ?: lookupTag.toSymbol(session)?.toSymbol(typeOrigin) { typeAnnotations += with(annotationGenerator) { it.toIrAnnotations() } } - ?: (lookupTag as? ConeClassLikeLookupTag)?.let(classifierStorage::getIrClassSymbolForNotFoundClass) + ?: (lookupTag as? ConeClassLikeLookupTag)?.let(classifiersGenerator::createIrClassSymbolForNotFoundClass) ?: return createErrorType() when { 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 6826f8c1970..73cc1c72423 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 @@ -452,11 +452,9 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi if (propertyAccessorForAnnotations != null) { convertAnnotationsForNonDeclaredMembers(propertyAccessorForAnnotations, origin) } - with(classifierStorage) { - setTypeParameters( - property, if (isSetter) ConversionTypeOrigin.SETTER else ConversionTypeOrigin.DEFAULT - ) - } + classifiersGenerator.setTypeParameters( + this, 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) @@ -686,9 +684,7 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi val containingClass = computeContainingClass(irParent) val parent = this if (function is FirSimpleFunction || function is FirConstructor) { - with(classifierStorage) { - setTypeParameters(function) - } + classifiersGenerator.setTypeParameters(this, function) } val typeOrigin = if (forSetter) ConversionTypeOrigin.SETTER else ConversionTypeOrigin.DEFAULT if (function is FirDefaultPropertySetter) { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrClassifiersGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrClassifiersGenerator.kt new file mode 100644 index 00000000000..419338f442d --- /dev/null +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrClassifiersGenerator.kt @@ -0,0 +1,570 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.backend.generators + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.fir.backend.* +import org.jetbrains.kotlin.fir.containingClassForLocalAttr +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.utils.* +import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression +import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass +import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag +import org.jetbrains.kotlin.fir.resolve.providers.firProvider +import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider +import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag +import org.jetbrains.kotlin.fir.symbols.Fir2IrClassSymbol +import org.jetbrains.kotlin.fir.symbols.Fir2IrEnumEntrySymbol +import org.jetbrains.kotlin.fir.symbols.Fir2IrTypeAliasSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.types.toLookupTag +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl +import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.symbols.impl.* +import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl +import org.jetbrains.kotlin.ir.util.IdSignature +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.name.SpecialNames +import org.jetbrains.kotlin.utils.addToStdlib.runUnless + +class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrComponents by components { + private val localClassesCreatedOnTheFly: MutableMap = mutableMapOf() + + private var processMembersOfClassesOnTheFlyImmediately = false + + internal fun setTypeParameters( + irOwner: IrTypeParametersContainer, + owner: FirTypeParameterRefsOwner, + typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT + ) { + irOwner.typeParameters = owner.typeParameters.mapIndexedNotNull { index, typeParameter -> + if (typeParameter !is FirTypeParameter) return@mapIndexedNotNull null + classifierStorage.getIrTypeParameter(typeParameter, index, irOwner.symbol, typeOrigin).apply { + parent = irOwner + if (superTypes.isEmpty()) { + superTypes = typeParameter.bounds.map { it.toIrType(typeOrigin) } + } + } + } + } + + private fun IrClass.declareTypeParameters(klass: FirClass) { + classifierStorage.preCacheTypeParameters(klass, symbol) + setTypeParameters(this, klass) + if (klass is FirRegularClass) { + val fieldsForContextReceiversOfCurrentClass = classifierStorage.getFieldsWithContextReceiversForClass(this, klass) + declarations.addAll(fieldsForContextReceiversOfCurrentClass) + } + } + + private fun IrClass.declareSupertypes(klass: FirClass) { + superTypes = klass.superTypeRefs.map { superTypeRef -> superTypeRef.toIrType() } + } + + private fun IrClass.declareValueClassRepresentation(klass: FirRegularClass) { + if (this !is Fir2IrLazyClass) { + valueClassRepresentation = computeValueClassRepresentation(klass) + } + } + + private fun FirRegularClass.enumClassModality(): Modality { + return when { + declarations.any { it is FirCallableDeclaration && it.modality == Modality.ABSTRACT } -> { + Modality.ABSTRACT + } + declarations.none { + it is FirEnumEntry && isEnumEntryWhichRequiresSubclass(it) + } -> { + Modality.FINAL + } + hasAbstractMembersInScope() -> { + Modality.ABSTRACT + } + else -> { + Modality.OPEN + } + } + } + + private fun FirRegularClass.hasAbstractMembersInScope(): Boolean { + val scope = unsubstitutedScope() + val names = scope.getCallableNames() + var hasAbstract = false + for (name in names) { + scope.processFunctionsByName(name) { + if (it.isAbstract) { + hasAbstract = true + } + } + if (hasAbstract) return true + scope.processPropertiesByName(name) { + if (it.isAbstract) { + hasAbstract = true + } + } + if (hasAbstract) return true + } + return false + } + + // TODO: it's worth to move this onTheFly stuff back to classifier storage + // This function is called when we refer local class earlier than we reach its declaration + // This can happen e.g. when implicit return type has a local class constructor + private fun createLocalIrClassOnTheFly(klass: FirClass): IrClass { + // finding the parent class that actually contains the [klass] in the tree - it is the root one that should be created on the fly + val classOrLocalParent = generateSequence(klass) { c -> + (c as? FirRegularClass)?.containingClassForLocalAttr?.let { lookupTag -> + (session.firProvider.symbolProvider.getSymbolByLookupTag(lookupTag)?.fir as? FirClass)?.takeIf { + it.declarations.contains(c) + } + } + }.last() + val result = converter.processLocalClassAndNestedClassesOnTheFly(classOrLocalParent, temporaryParent) + // Note: usually member creation and f/o binding is delayed till non-local classes are processed in Fir2IrConverter + // If non-local classes are already created (this means we are in body translation) we do everything immediately + // The last variant is possible for local variables like 'val a = object : Any() { ... }' + if (processMembersOfClassesOnTheFlyImmediately) { + converter.processClassMembers(classOrLocalParent, result) + converter.bindFakeOverridesInClass(result) + } else { + localClassesCreatedOnTheFly[classOrLocalParent] = result + } + return if (classOrLocalParent === klass) result + else (classifierStorage.getCachedIrClass(klass) + ?: error("Assuming that all nested classes of ${classOrLocalParent.classId.asString()} should already be cached")) + } + + // Note: this function is called exactly once, right after Fir2IrConverter finished f/o binding for regular classes + fun processMembersOfClassesCreatedOnTheFly() { + // After the call of this function, members of local classes may be processed immediately + // Before the call it's not possible, because f/o binding for regular classes isn't done yet + processMembersOfClassesOnTheFlyImmediately = true + for ((klass, irClass) in localClassesCreatedOnTheFly) { + converter.processClassMembers(klass, irClass) + // See the problem from KT-57441 +// class Wrapper { +// private val dummy = object: Bar {} +// private val bar = object: Bar by dummy {} +// } +// interface Bar { +// val foo: String +// get() = "" +// } + // When we are building bar.foo fake override, we should call dummy.foo, + // so we should have object : Bar.foo fake override to be built and bound. + converter.bindFakeOverridesInClass(irClass) + } + localClassesCreatedOnTheFly.clear() + } + + fun processClassHeader(klass: FirClass, irClass: IrClass = classifierStorage.getCachedIrClass(klass)!!): IrClass { + irClass.declareTypeParameters(klass) + irClass.setThisReceiver(klass.typeParameters) + irClass.declareSupertypes(klass) + if (klass is FirRegularClass) { + irClass.declareValueClassRepresentation(klass) + } + return irClass + } + + private fun IrClass.setThisReceiver(typeParameters: List) { + symbolTable.enterScope(this) + val typeArguments = typeParameters.map { + IrSimpleTypeImpl(classifierStorage.getIrTypeParameterSymbol(it.symbol, ConversionTypeOrigin.DEFAULT), false, emptyList(), emptyList()) + } + thisReceiver = declareThisReceiverParameter( + thisType = IrSimpleTypeImpl(symbol, false, typeArguments, emptyList()), + thisOrigin = IrDeclarationOrigin.INSTANCE_RECEIVER + ) + symbolTable.leaveScope(this) + } + + + private fun declareIrTypeAlias(signature: IdSignature?, factory: (IrTypeAliasSymbol) -> IrTypeAlias): IrTypeAlias = + if (signature == null) + factory(IrTypeAliasSymbolImpl()) + else + symbolTable.declareTypeAlias(signature, { Fir2IrTypeAliasSymbol(signature) }, factory) + + fun createIrTypeAlias( + typeAlias: FirTypeAlias, + parent: IrDeclarationParent + ): IrTypeAlias = typeAlias.convertWithOffsets { startOffset, endOffset -> + val signature = signatureComposer.composeSignature(typeAlias) + declareIrTypeAlias(signature) { symbol -> + classifierStorage.preCacheTypeParameters(typeAlias, symbol) + val irTypeAlias = irFactory.createTypeAlias( + startOffset = startOffset, + endOffset = endOffset, + origin = IrDeclarationOrigin.DEFINED, + name = typeAlias.name, + visibility = components.visibilityConverter.convertToDescriptorVisibility(typeAlias.visibility), + symbol = symbol, + isActual = typeAlias.isActual, + expandedType = typeAlias.expandedTypeRef.toIrType(), + ).apply { + this.parent = parent + setTypeParameters(this, typeAlias) + if (parent is IrFile) { + parent.declarations += this + } + } + typeAliasCache[typeAlias] = irTypeAlias + irTypeAlias + } + } + + fun declareIrClass(signature: IdSignature?, factory: (IrClassSymbol) -> IrClass): IrClass { + return if (signature == null) + factory(IrClassSymbolImpl()) + else + symbolTable.declareClass(signature, { Fir2IrClassSymbol(signature) }, factory) + } + + fun createIrClass( + regularClass: FirRegularClass, + parent: IrDeclarationParent, + predefinedOrigin: IrDeclarationOrigin? = null + ): IrClass { + val visibility = regularClass.visibility + val modality = when (regularClass.classKind) { + ClassKind.ENUM_CLASS -> regularClass.enumClassModality() + ClassKind.ANNOTATION_CLASS -> Modality.OPEN + else -> regularClass.modality ?: Modality.FINAL + } + val signature = runUnless(regularClass.isLocal || !configuration.linkViaSignatures) { + signatureComposer.composeSignature(regularClass) + } + val irClass = regularClass.convertWithOffsets { startOffset, endOffset -> + declareIrClass(signature) { symbol -> + irFactory.createClass( + startOffset = startOffset, + endOffset = endOffset, + origin = regularClass.computeIrOrigin(predefinedOrigin), + name = regularClass.name, + visibility = components.visibilityConverter.convertToDescriptorVisibility(visibility), + symbol = symbol, + kind = regularClass.classKind, + modality = modality, + isExternal = regularClass.isExternal, + isCompanion = regularClass.isCompanion, + isInner = regularClass.isInner, + isData = regularClass.isData, + isValue = regularClass.isInline, + isExpect = regularClass.isExpect, + isFun = regularClass.isFun + ).apply { + metadata = FirMetadataSource.Class(regularClass) + } + } + } + irClass.parent = parent + if (regularClass.visibility == Visibilities.Local) { + localStorage[regularClass] = irClass + } else { + classCache[regularClass] = irClass + } + return irClass + } + + fun createAnonymousObject( + anonymousObject: FirAnonymousObject, + visibility: Visibility = Visibilities.Local, + name: Name = SpecialNames.NO_NAME_PROVIDED, + irParent: IrDeclarationParent? = null + ): IrClass { + val origin = IrDeclarationOrigin.DEFINED + val modality = Modality.FINAL + val irAnonymousObject = anonymousObject.convertWithOffsets { startOffset, endOffset -> + irFactory.createClass( + startOffset = startOffset, + endOffset = endOffset, + origin = origin, + name = name, + visibility = components.visibilityConverter.convertToDescriptorVisibility(visibility), + symbol = IrClassSymbolImpl(), + kind = anonymousObject.classKind, + modality = modality, + ).apply { + metadata = FirMetadataSource.Class(anonymousObject) + } + } + if (irParent != null) { + irAnonymousObject.parent = irParent + } + localStorage[anonymousObject] = irAnonymousObject + return irAnonymousObject + } + + fun createCodeFragmentClass(codeFragment: FirCodeFragment, containingFile: IrFile): IrClass { + val conversionData = codeFragment.conversionData + val signature = signatureComposer.composeSignature(codeFragment) + + val irClass = codeFragment.convertWithOffsets { startOffset, endOffset -> + declareIrClass(signature) { symbol -> + irFactory.createClass( + startOffset, + endOffset, + IrDeclarationOrigin.DEFINED, + conversionData.classId.shortClassName, + DescriptorVisibilities.PUBLIC, + symbol, + ClassKind.CLASS, + Modality.FINAL, + isExternal = false, + isCompanion = false, + isInner = false, + isData = false, + isValue = false, + isExpect = false, + isFun = false + ).apply { + metadata = FirMetadataSource.CodeFragment(codeFragment) + parent = containingFile + typeParameters = emptyList() + thisReceiver = declareThisReceiverParameter( + thisType = IrSimpleTypeImpl(symbol, false, emptyList(), emptyList()), + thisOrigin = IrDeclarationOrigin.INSTANCE_RECEIVER + ) + superTypes = listOf(irBuiltIns.anyType) + } + } + } + codeFragmentCache[codeFragment] = irClass + return irClass + } + + private fun getIrAnonymousObjectForEnumEntry(anonymousObject: FirAnonymousObject, name: Name, irParent: IrClass?): IrClass { + localStorage[anonymousObject]?.let { return it } + val irAnonymousObject = classifierStorage.createAndCacheAnonymousObject(anonymousObject, Visibilities.Private, name, irParent) + processClassHeader(anonymousObject, irAnonymousObject) + return irAnonymousObject + } + + fun createIrTypeParameterWithBounds( + typeParameter: FirTypeParameter, + index: Int, + ownerSymbol: IrSymbol, + typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT, + ): IrTypeParameter { + val irTypeParameter = createIrTypeParameterWithoutBounds(typeParameter, index, ownerSymbol, typeOrigin) + irTypeParameter.superTypes = typeParameter.bounds.map { it.toIrType() } + return irTypeParameter + } + + fun createIrTypeParameterWithoutBounds( + typeParameter: FirTypeParameter, + index: Int, + ownerSymbol: IrSymbol, + typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT, + ): IrTypeParameter { + require(index >= 0) + val origin = typeParameter.computeIrOrigin() + val irTypeParameter = with(typeParameter) { + convertWithOffsets { startOffset, endOffset -> + signatureComposer.composeTypeParameterSignature( + index, ownerSymbol.signature + )?.let { signature -> + if (ownerSymbol is IrClassifierSymbol) { + symbolTable.declareGlobalTypeParameter( + signature, + symbolFactory = { IrTypeParameterPublicSymbolImpl(signature) } + ) { symbol -> + irFactory.createTypeParameter( + startOffset = startOffset, + endOffset = endOffset, + origin = origin, + name = name, + symbol = symbol, + variance = variance, + index = if (index < 0) 0 else index, + isReified = isReified, + ) + } + } else { + symbolTable.declareScopedTypeParameter( + signature, + symbolFactory = { IrTypeParameterPublicSymbolImpl(signature) } + ) { symbol -> + irFactory.createTypeParameter( + startOffset = startOffset, + endOffset = endOffset, + origin = origin, + name = name, + symbol = symbol, + variance = variance, + index = if (index < 0) 0 else index, + isReified = isReified, + ) + } + + } + } ?: irFactory.createTypeParameter( + startOffset = startOffset, + endOffset = endOffset, + origin = origin, + name = name, + symbol = IrTypeParameterSymbolImpl(), + variance = variance, + index = if (index < 0) 0 else index, + isReified = isReified, + ) + } + } + + // Cache the type parameter BEFORE processing its bounds/supertypes, to properly handle recursive type bounds. + if (typeOrigin.forSetter) { + typeParameterCacheForSetter[typeParameter] = irTypeParameter + } else { + typeParameterCache[typeParameter] = irTypeParameter + } + annotationGenerator.generate(irTypeParameter, typeParameter) + return irTypeParameter + } + + private fun declareIrEnumEntry(signature: IdSignature?, factory: (IrEnumEntrySymbol) -> IrEnumEntry): IrEnumEntry { + return if (signature == null) + factory(IrEnumEntrySymbolImpl()) + else + symbolTable.declareEnumEntry(signature, { Fir2IrEnumEntrySymbol(signature) }, factory) + } + + fun createIrEnumEntry( + enumEntry: FirEnumEntry, + irParent: IrClass?, + predefinedOrigin: IrDeclarationOrigin? = null, + ): IrEnumEntry { + return enumEntry.convertWithOffsets { startOffset, endOffset -> + val signature = signatureComposer.composeSignature(enumEntry) + val result = declareIrEnumEntry(signature) { symbol -> + val origin = enumEntry.computeIrOrigin(predefinedOrigin) + irFactory.createEnumEntry( + startOffset = startOffset, + endOffset = endOffset, + origin = origin, + name = enumEntry.name, + symbol = symbol, + ).apply { + declarationStorage.enterScope(this.symbol) + if (irParent != null) { + this.parent = irParent + } + if (isEnumEntryWhichRequiresSubclass(enumEntry)) { + // An enum entry with its own members requires an anonymous object generated. + // Otherwise, this is a default-ish enum entry whose initializer would be a delegating constructor call, + // which will be translated via visitor later. + val klass = getIrAnonymousObjectForEnumEntry( + (enumEntry.initializer as FirAnonymousObjectExpression).anonymousObject, enumEntry.name, irParent + ) + this.correspondingClass = klass + } + declarationStorage.leaveScope(this.symbol) + } + } + enumEntryCache[enumEntry] = result + result + } + } + + private fun isEnumEntryWhichRequiresSubclass(enumEntry: FirEnumEntry): Boolean { + val initializer = enumEntry.initializer + return initializer is FirAnonymousObjectExpression && initializer.anonymousObject.declarations.any { it !is FirConstructor } + } + + @OptIn(IrSymbolInternals::class) + fun createIrClassSymbolForNotFoundClass(classLikeLookupTag: ConeClassLikeLookupTag): IrClassSymbol { + val classId = classLikeLookupTag.classId + val signature = IdSignature.CommonSignature( + packageFqName = classId.packageFqName.asString(), + declarationFqName = classId.relativeClassName.asString(), + id = 0, + mask = 0, + description = null, + ) + + val parentId = classId.outerClassId + val parentClass = parentId?.let { createIrClassSymbolForNotFoundClass(it.toLookupTag()) } + val irParent = parentClass?.owner ?: declarationStorage.getIrExternalPackageFragment(classId.packageFqName) + + return symbolTable.referenceClass(signature, { Fir2IrClassSymbol(signature) }) { + irFactory.createClass( + startOffset = UNDEFINED_OFFSET, + endOffset = UNDEFINED_OFFSET, + origin = IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB, + name = classId.shortClassName, + visibility = DescriptorVisibilities.DEFAULT_VISIBILITY, + symbol = it, + kind = ClassKind.CLASS, + modality = Modality.FINAL, + ).apply { + parent = irParent + } + } + } + + // TODO: should be decomposed + fun createIrClassSymbolByFirSymbol(firClassSymbol: FirClassSymbol<*>): IrClassSymbol { + val firClass = firClassSymbol.fir + classifierStorage.getCachedIrClass(firClass)?.let { return it.symbol } + if (firClass is FirAnonymousObject || firClass is FirRegularClass && firClass.visibility == Visibilities.Local) { + return createLocalIrClassOnTheFly(firClass).symbol + } + firClass as FirRegularClass + val classId = firClassSymbol.classId + val parentId = classId.outerClassId + val parentClass = parentId?.let { session.symbolProvider.getClassLikeSymbolByClassId(it) } + val irParent = declarationStorage.findIrParent(classId.packageFqName, parentClass?.toLookupTag(), firClassSymbol, firClass.origin)!! + + // firClass may be referenced by some parent's type parameters as a bound. In that case, getIrClassSymbol will be called recursively. + classifierStorage.getCachedIrClass(firClass)?.let { return it.symbol } + + val irClass = lazyDeclarationsGenerator.createIrLazyClass(firClass, irParent) + classCache[firClass] = irClass + // NB: this is needed to prevent recursions in case of self bounds + (irClass as Fir2IrLazyClass).prepareTypeParameters() + + return irClass.symbol + } + + + fun createIrTypeParameterForNonCachedDeclaration(firTypeParameter: FirTypeParameter): IrTypeParameterSymbol { + val firTypeParameterOwnerSymbol = firTypeParameter.containingDeclarationSymbol + val firTypeParameterOwner = firTypeParameterOwnerSymbol.fir as FirTypeParameterRefsOwner + val index = firTypeParameterOwner.typeParameters.indexOf(firTypeParameter).also { check(it >= 0) } + + val isSetter = firTypeParameterOwner is FirPropertyAccessor && firTypeParameterOwner.isSetter + val conversionTypeOrigin = if (isSetter) ConversionTypeOrigin.SETTER else ConversionTypeOrigin.DEFAULT + + return createIrTypeParameterWithoutBounds(firTypeParameter, index, IrTypeParameterSymbolImpl(), conversionTypeOrigin).apply { + superTypes = firTypeParameter.bounds.map { it.toIrType(typeConverter) } + }.symbol + } + + private val temporaryParent by lazy { + irFactory.createSimpleFunction( + startOffset = UNDEFINED_OFFSET, + endOffset = UNDEFINED_OFFSET, + origin = IrDeclarationOrigin.DEFINED, + name = Name.special(""), + visibility = DescriptorVisibilities.PRIVATE, + isInline = false, + isExpect = false, + returnType = irBuiltIns.unitType, + modality = Modality.FINAL, + symbol = IrSimpleFunctionSymbolImpl(), + isTailrec = false, + isSuspend = false, + isOperator = false, + isInfix = false, + isExternal = false, + ).apply { + parent = IrExternalPackageFragmentImpl(IrExternalPackageFragmentSymbolImpl(), FqName.ROOT) + } + } +} diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyDeclarationsGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyDeclarationsGenerator.kt index 659bd0c0c66..36d9dc23ea6 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyDeclarationsGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyDeclarationsGenerator.kt @@ -7,8 +7,11 @@ package org.jetbrains.kotlin.fir.backend.generators import org.jetbrains.kotlin.fir.backend.Fir2IrComponents import org.jetbrains.kotlin.fir.backend.convertWithOffsets +import org.jetbrains.kotlin.fir.backend.irOrigin import org.jetbrains.kotlin.fir.backend.isStubPropertyForPureField +import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.dispatchReceiverClassLookupTagOrNull import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride @@ -16,13 +19,13 @@ import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyProperty import org.jetbrains.kotlin.fir.lazy.Fir2IrLazySimpleFunction import org.jetbrains.kotlin.fir.originalForSubstitutionOverride +import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.symbols.Fir2IrPropertySymbol -import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin -import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent -import org.jetbrains.kotlin.ir.declarations.IrProperty -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbolInternals import org.jetbrains.kotlin.ir.util.IdSignature +import org.jetbrains.kotlin.utils.addToStdlib.runIf class Fir2IrLazyDeclarationsGenerator(val components: Fir2IrComponents) : Fir2IrComponents by components { internal fun createIrLazyFunction( @@ -87,4 +90,18 @@ class Fir2IrLazyDeclarationsGenerator(val components: Fir2IrComponents) : Fir2Ir return irProperty } + fun createIrLazyClass( + firClass: FirRegularClass, + irParent: IrDeclarationParent, + ): IrClass = firClass.convertWithOffsets { startOffset, endOffset -> + val firClassOrigin = firClass.irOrigin(session.firProvider) + val signature = runIf(configuration.linkViaSignatures) { + signatureComposer.composeSignature(firClass) + } + classifiersGenerator.declareIrClass(signature) { symbol -> + Fir2IrLazyClass(components, startOffset, endOffset, firClassOrigin, firClass, symbol).apply { + parent = irParent + } + } + } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt index 7fa2e10b8d7..649d76c49fb 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt @@ -191,11 +191,7 @@ class Fir2IrLazyProperty( }.apply { parent = this@Fir2IrLazyProperty.parent correspondingPropertySymbol = this@Fir2IrLazyProperty.symbol - with(classifierStorage) { - setTypeParameters( - this@Fir2IrLazyProperty.fir, ConversionTypeOrigin.DEFAULT - ) - } + classifiersGenerator.setTypeParameters(this, this@Fir2IrLazyProperty.fir, ConversionTypeOrigin.DEFAULT) } } @@ -222,11 +218,7 @@ class Fir2IrLazyProperty( ).apply { parent = this@Fir2IrLazyProperty.parent correspondingPropertySymbol = this@Fir2IrLazyProperty.symbol - with(classifierStorage) { - setTypeParameters( - this@Fir2IrLazyProperty.fir, ConversionTypeOrigin.SETTER - ) - } + classifiersGenerator.setTypeParameters(this, this@Fir2IrLazyProperty.fir, ConversionTypeOrigin.SETTER) } } }