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 94216d6695c..5a0f3f842e7 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 @@ -8,6 +8,9 @@ package org.jetbrains.kotlin.fir.backend import com.intellij.psi.PsiCompiledElement import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction +import org.jetbrains.kotlin.fir.declarations.FirVariable import org.jetbrains.kotlin.fir.expressions.FirConstExpression import org.jetbrains.kotlin.fir.expressions.FirConstKind import org.jetbrains.kotlin.fir.psi @@ -31,6 +34,7 @@ import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments import org.jetbrains.kotlin.types.Variance @@ -215,3 +219,38 @@ private fun FirConstKind<*>.toIrConstKind(): IrConstKind<*> = when (this) { FirConstKind.Double -> IrConstKind.Double FirConstKind.IntegerLiteral -> throw IllegalArgumentException() } + +internal fun FirClass<*>.collectCallableNamesFromSupertypes(session: FirSession, result: MutableList = mutableListOf()): List { + for (superTypeRef in superTypeRefs) { + superTypeRef.collectCallableNamesFromThisAndSupertypes(session, result) + } + return result +} + +private fun FirTypeRef.collectCallableNamesFromThisAndSupertypes( + session: FirSession, + result: MutableList = mutableListOf() +): List { + if (this is FirResolvedTypeRef) { + val superType = type + if (superType is ConeClassLikeType) { + when (val superSymbol = superType.lookupTag.toSymbol(session)) { + is FirClassSymbol -> { + val superClass = superSymbol.fir as FirClass<*> + for (declaration in superClass.declarations) { + when (declaration) { + is FirSimpleFunction -> result += declaration.name + is FirVariable<*> -> result += declaration.name + } + } + superClass.collectCallableNamesFromSupertypes(session, result) + } + is FirTypeAliasSymbol -> { + val superAlias = superSymbol.fir + superAlias.expandedTypeRef.collectCallableNamesFromThisAndSupertypes(session, result) + } + } + } + } + return result +} 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 5ee621c3085..bc6a8279447 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 @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.descriptors.FirPackageFragmentDescriptor import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.* +import org.jetbrains.kotlin.fir.scopes.impl.FirClassSubstitutionScope import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.FirTypeRef @@ -159,7 +160,7 @@ class Fir2IrDeclarationStorage( return this } - fun getIrClass(klass: FirClass<*>, setParent: Boolean = true): IrClass { + fun getIrClass(klass: FirClass<*>, setParentAndContent: Boolean = true): IrClass { val regularClass = klass as? FirRegularClass fun create(): IrClass { @@ -187,7 +188,7 @@ class Fir2IrDeclarationStorage( isFun = false // TODO FirRegularClass.isFun ).apply { descriptor.bind(this) - if (setParent && regularClass != null) { + if (setParentAndContent && regularClass != null) { val classId = regularClass.classId val parentId = classId.outerClassId if (parentId != null) { @@ -216,9 +217,57 @@ class Fir2IrDeclarationStorage( return created } // NB: klass can be either FirRegularClass or FirAnonymousObject - return classCache.getOrPut(klass as FirRegularClass, { create() }) { - it.declareSupertypesAndTypeParameters(klass) - it.setThisReceiver() + return classCache.getOrPut(klass as FirRegularClass, { create() }) { irClass -> + irClass.declareSupertypesAndTypeParameters(klass) + irClass.setThisReceiver() + if (setParentAndContent && regularClass != null && + regularClass.symbol.classId.packageFqName.startsWith(Name.identifier("kotlin")) + ) { + // Note: yet this is necessary only for *Range / *Progression classes + // due to BE optimizations (for lowering) that use their first / last / step members + // TODO: think how to refactor this piece of code and/or merge it with similar Fir2IrVisitor fragment + val processedNames = mutableSetOf() + for (declaration in regularClass.declarations) { + irClass.declarations += when (declaration) { + is FirSimpleFunction -> { + processedNames += declaration.name + getIrFunction(declaration, irClass, shouldLeaveScope = true) + } + is FirProperty -> { + processedNames += declaration.name + getIrProperty(declaration, irClass) + } + is FirConstructor -> getIrConstructor(declaration, irClass, shouldLeaveScope = true) + is FirRegularClass -> getIrClass(declaration) + else -> continue + } + } + val allNames = regularClass.collectCallableNamesFromSupertypes(session) + val scope = regularClass.buildUseSiteMemberScope(session, ScopeSession()) + if (scope != null) { + for (name in allNames) { + if (name in processedNames) continue + processedNames += name + scope.processFunctionsByName(name) { functionSymbol -> + if (functionSymbol is FirNamedFunctionSymbol) { + val fakeOverrideSymbol = + FirClassSubstitutionScope.createFakeOverrideFunction(session, functionSymbol.fir, functionSymbol) + irClass.declarations += getIrFunction(fakeOverrideSymbol.fir, irClass, shouldLeaveScope = true) + } + } + scope.processPropertiesByName(name) { propertySymbol -> + if (propertySymbol is FirPropertySymbol) { + val fakeOverrideSymbol = + FirClassSubstitutionScope.createFakeOverrideProperty(session, propertySymbol.fir, propertySymbol) + irClass.declarations += getIrProperty(fakeOverrideSymbol.fir, irClass) + } + } + } + } + for (irDeclaration in irClass.declarations) { + irDeclaration.parent = irClass + } + } } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt index f1f330c543b..7841ccb4718 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt @@ -183,44 +183,12 @@ class Fir2IrVisitor( return irEnumEntry.setParentByParentStack() } - private fun FirTypeRef.collectCallableNamesFromThisAndSupertypes(result: MutableList = mutableListOf()): List { - if (this is FirResolvedTypeRef) { - val superType = type - if (superType is ConeClassLikeType) { - when (val superSymbol = superType.lookupTag.toSymbol(this@Fir2IrVisitor.session)) { - is FirClassSymbol -> { - val superClass = superSymbol.fir as FirClass<*> - for (declaration in superClass.declarations) { - when (declaration) { - is FirSimpleFunction -> result += declaration.name - is FirVariable<*> -> result += declaration.name - } - } - superClass.collectCallableNamesFromSupertypes(result) - } - is FirTypeAliasSymbol -> { - val superAlias = superSymbol.fir - superAlias.expandedTypeRef.collectCallableNamesFromThisAndSupertypes(result) - } - } - } - } - return result - } - - private fun FirClass<*>.collectCallableNamesFromSupertypes(result: MutableList = mutableListOf()): List { - for (superTypeRef in superTypeRefs) { - superTypeRef.collectCallableNamesFromThisAndSupertypes(result) - } - return result - } - private fun FirClass<*>.getPrimaryConstructorIfAny(): FirConstructor? = declarations.filterIsInstance().firstOrNull()?.takeIf { it.isPrimary } private fun IrClass.addFakeOverrides(klass: FirClass<*>, processedCallableNames: MutableList) { if (fakeOverrideMode == FakeOverrideMode.NONE) return - val superTypesCallableNames = klass.collectCallableNamesFromSupertypes() + val superTypesCallableNames = klass.collectCallableNamesFromSupertypes(session) val useSiteMemberScope = (klass as? FirRegularClass)?.buildUseSiteMemberScope(session, ScopeSession()) ?: return for (name in superTypesCallableNames) { if (name in processedCallableNames) continue @@ -315,7 +283,7 @@ class Fir2IrVisitor( } override fun visitRegularClass(regularClass: FirRegularClass, data: Any?): IrElement { - return declarationStorage.getIrClass(regularClass, setParent = false) + return declarationStorage.getIrClass(regularClass, setParentAndContent = false) .setParentByParentStack() .withParent { setClassContent(regularClass) @@ -360,7 +328,7 @@ class Fir2IrVisitor( lastClass } else { val firClass = classLikeSymbol.fir as FirClass<*> - declarationStorage.getIrClass(firClass, setParent = false) + declarationStorage.getIrClass(firClass, setParentAndContent = false) } } } @@ -850,7 +818,7 @@ class Fir2IrVisitor( it is FirAnonymousObject || it is FirRegularClass && it.classKind == ClassKind.OBJECT } firClass?.convertWithOffsets { startOffset, endOffset -> - val irClass = declarationStorage.getIrClass(firClass, setParent = false) + val irClass = declarationStorage.getIrClass(firClass, setParentAndContent = false) IrGetObjectValueImpl(startOffset, endOffset, irClass.defaultType, irClass.symbol) } } @@ -928,7 +896,7 @@ class Fir2IrVisitor( it is FirAnonymousObject || it is FirRegularClass && it.classKind == ClassKind.OBJECT } if (firObject != null) { - val irObject = declarationStorage.getIrClass(firObject, setParent = false) + val irObject = declarationStorage.getIrClass(firObject, setParentAndContent = false) if (irObject != classStack.lastOrNull()) { return thisReceiverExpression.convertWithOffsets { startOffset, endOffset -> IrGetObjectValueImpl(startOffset, endOffset, irObject.defaultType, irObject.symbol) @@ -1360,7 +1328,8 @@ class Fir2IrVisitor( FirOperation.MINUS_ASSIGN, FirOperation.TIMES_ASSIGN, FirOperation.DIV_ASSIGN, FirOperation.REM_ASSIGN, FirOperation.IS, FirOperation.NOT_IS, - FirOperation.AS, FirOperation.SAFE_AS -> { + FirOperation.AS, FirOperation.SAFE_AS + -> { TODO("Should not be here: incompatible operation in FirOperatorCall: $operation") } }