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 4bcd16d32f3..96771bc161c 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 @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.backend.evaluate.evaluateConstants import org.jetbrains.kotlin.fir.backend.generators.AnnotationGenerator import org.jetbrains.kotlin.fir.backend.generators.CallAndReferenceGenerator +import org.jetbrains.kotlin.fir.backend.generators.DataClassMembersGenerator import org.jetbrains.kotlin.fir.backend.generators.FakeOverrideGenerator import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor @@ -23,6 +24,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.WrappedDeclarationDescriptor import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi2ir.PsiSourceManager import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions @@ -89,40 +91,90 @@ class Fir2IrConverter( it, irClass, isLocal = true ) } + val processedCallableNames = mutableSetOf() for (declaration in sortBySynthetic(anonymousObject.declarations)) { if (declaration is FirRegularClass) { registerClassAndNestedClasses(declaration, irClass) processClassAndNestedClassHeaders(declaration) } val irDeclaration = processMemberDeclaration(declaration, anonymousObject, irClass) ?: continue + when (declaration) { + is FirSimpleFunction -> processedCallableNames += declaration.name + is FirProperty -> processedCallableNames += declaration.name + } irClass.declarations += irDeclaration } - return irClass - } + // Add delegated members *before* fake override generations. + // Otherwise, fake overrides for delegated members, which are redundant, will be added. + processedCallableNames += delegatedMemberNames(irClass) + with(fakeOverrideGenerator) { + irClass.addFakeOverrides(anonymousObject, processedCallableNames) + } - // Sort declarations so that all non-synthetic declarations are before synthetic ones. - // This is needed because converting synthetic fields for implementation delegation needs to know - // existing declarations in the class to avoid adding redundant delegated members. - private fun sortBySynthetic(declarations: List) : Iterable { - return declarations.sortedBy { it.isSynthetic } + return irClass } private fun processClassMembers( regularClass: FirRegularClass, irClass: IrClass = classifierStorage.getCachedIrClass(regularClass)!! ): IrClass { - regularClass.getPrimaryConstructorIfAny()?.let { - irClass.declarations += declarationStorage.createIrConstructor( - it, irClass, isLocal = regularClass.isLocal - ) + val irConstructor = regularClass.getPrimaryConstructorIfAny()?.let { + declarationStorage.createIrConstructor(it, irClass, isLocal = regularClass.isLocal) } + if (irConstructor != null) { + irClass.declarations += irConstructor + } + val processedCallableNames = mutableSetOf() for (declaration in sortBySynthetic(regularClass.declarations)) { val irDeclaration = processMemberDeclaration(declaration, regularClass, irClass) ?: continue + when (declaration) { + is FirSimpleFunction -> processedCallableNames += declaration.name + is FirProperty -> processedCallableNames += declaration.name + } irClass.declarations += irDeclaration } + // Add delegated members *before* fake override generations. + // Otherwise, fake overrides for delegated members, which are redundant, will be added. + processedCallableNames += delegatedMemberNames(irClass) + // Add synthetic members *before* fake override generations. + // Otherwise, redundant members, e.g., synthetic toString _and_ fake override toString, will be added. + if (irConstructor != null && (irClass.isInline || irClass.isData)) { + declarationStorage.enterScope(irConstructor) + val dataClassMembersGenerator = DataClassMembersGenerator(components) + if (irClass.isInline) { + processedCallableNames += dataClassMembersGenerator.generateInlineClassMembers(regularClass, irClass) + } + if (irClass.isData) { + processedCallableNames += dataClassMembersGenerator.generateDataClassMembers(regularClass, irClass) + } + declarationStorage.leaveScope(irConstructor) + } + with(fakeOverrideGenerator) { + irClass.addFakeOverrides(regularClass, processedCallableNames) + } + return irClass } + private fun delegatedMemberNames(irClass: IrClass): List { + return irClass.declarations.filter { + it.origin == IrDeclarationOrigin.DELEGATED_MEMBER + }.mapNotNull { + when (it) { + is IrSimpleFunction -> it.name + is IrProperty -> it.name + else -> null + } + } + } + + // Sort declarations so that all non-synthetic declarations are before synthetic ones. + // This is needed because converting synthetic fields for implementation delegation needs to know + // existing declarations in the class to avoid adding redundant delegated members. + private fun sortBySynthetic(declarations: List): Iterable { + return declarations.sortedBy { it.isSynthetic } + } + private fun registerClassAndNestedClasses(regularClass: FirRegularClass, parent: IrDeclarationParent): IrClass { val irClass = classifierStorage.registerIrClass(regularClass, parent) regularClass.declarations.forEach { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt index a03be4b208c..2620473c07f 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt @@ -15,19 +15,13 @@ import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.fullyExpandedType -import org.jetbrains.kotlin.fir.scopes.ProcessorAction -import org.jetbrains.kotlin.fir.scopes.processDirectlyOverriddenProperties -import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol -import org.jetbrains.kotlin.fir.symbols.impl.unwrapSubstitutionOverrides import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrFieldAccessExpression import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol -import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol -import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.util.constructedClassType import org.jetbrains.kotlin.ir.util.isAnnotationClass @@ -61,32 +55,7 @@ internal class ClassMemberGenerator( convertFunctionContent(irPrimaryConstructor, primaryConstructor, containingClass = klass) } } - val processedCallableNames = klass.declarations.mapNotNullTo(mutableSetOf()) { - when (it) { - is FirSimpleFunction -> it.name - is FirProperty -> it.name - else -> null - } - } - // Add delegated members *before* fake override generations. - // Otherwise, fake overrides for delegated members, which are redundant, will be added. - irClass.declarations.filter { - it.origin == IrDeclarationOrigin.DELEGATED_MEMBER - }.forEach { - when (it) { - is IrSimpleFunction -> processedCallableNames += it.name - is IrProperty -> processedCallableNames += it.name - } - } - // Add synthetic members *before* fake override generations. - // Otherwise, redundant members, e.g., synthetic toString _and_ fake override toString, will be added. - if (irClass.isInline && klass.getPrimaryConstructorIfAny() != null) { - processedCallableNames += DataClassMembersGenerator(components).generateInlineClassMembers(klass, irClass) - } - if (irClass.isData && klass.getPrimaryConstructorIfAny() != null) { - processedCallableNames += DataClassMembersGenerator(components).generateDataClassMembers(klass, irClass) - } - with(fakeOverrideGenerator) { irClass.addFakeOverrides(klass, processedCallableNames) } + fakeOverrideGenerator.bindOverriddenSymbols(irClass.declarations) klass.declarations.forEach { declaration -> when { declaration is FirTypeAlias -> { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt index e2c6e93a398..2d8df2a0557 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt @@ -33,6 +33,9 @@ class FakeOverrideGenerator( private val fakeOverrideMode: FakeOverrideMode ) { + private val baseFunctionSymbols = mutableMapOf() + private val basePropertySymbols = mutableMapOf() + private fun IrSimpleFunction.withFunction(f: IrSimpleFunction.() -> Unit): IrSimpleFunction { return conversionScope.withFunction(this, f) } @@ -98,11 +101,9 @@ class FakeOverrideGenerator( // In fake overrides, parent logic is a bit specific, because // parent of *original* function (base class) is used for dispatch receiver, // but fake override itself uses parent from its containing (derived) class - val overriddenSymbol = declarationStorage.getIrFunctionSymbol(baseSymbol) as IrSimpleFunctionSymbol irFunction.parent = this - result += irFunction.withFunction { - overriddenSymbols = listOf(overriddenSymbol) - } + baseFunctionSymbols[irFunction] = baseSymbol + result += irFunction } else if (fakeOverrideMode != FakeOverrideMode.SUBSTITUTION && originalFunction.allowsToHaveFakeOverrideIn(klass)) { // Trivial fake override case val fakeOverrideSymbol = FirClassSubstitutionScope.createFakeOverrideFunction( @@ -123,11 +124,9 @@ class FakeOverrideGenerator( if (irFunction.returnType.containsErrorType() || irFunction.valueParameters.any { it.type.containsErrorType() }) { return@processFunctionsByName } - val overriddenSymbol = declarationStorage.getIrFunctionSymbol(baseSymbol) as IrSimpleFunctionSymbol irFunction.parent = this - result += irFunction.withFunction { - overriddenSymbols = listOf(overriddenSymbol) - } + baseFunctionSymbols[irFunction] = baseSymbol + result += irFunction } } } @@ -149,10 +148,8 @@ class FakeOverrideGenerator( isLocal = isLocal ) irProperty.parent = this - result += irProperty.withProperty { - discardAccessorsAccordingToBaseVisibility(baseSymbol) - setOverriddenSymbolsForAccessors(declarationStorage, originalProperty, firOverriddenSymbol = baseSymbol) - } + basePropertySymbols[irProperty] = baseSymbol + result += irProperty } else if (fakeOverrideMode != FakeOverrideMode.SUBSTITUTION && originalProperty.allowsToHaveFakeOverrideIn(klass)) { // Trivial fake override case val fakeOverrideSymbol = FirClassSubstitutionScope.createFakeOverrideProperty( @@ -175,10 +172,8 @@ class FakeOverrideGenerator( return@processPropertiesByName } irProperty.parent = this - result += irProperty.withProperty { - discardAccessorsAccordingToBaseVisibility(baseSymbol) - setOverriddenSymbolsForAccessors(declarationStorage, fakeOverrideProperty, firOverriddenSymbol = baseSymbol) - } + basePropertySymbols[irProperty] = baseSymbol + result += irProperty } } } @@ -186,6 +181,28 @@ class FakeOverrideGenerator( return result } + fun bindOverriddenSymbols(declarations: List) { + for (declaration in declarations) { + if (declaration.origin != IrDeclarationOrigin.FAKE_OVERRIDE) continue + when (declaration) { + is IrSimpleFunction -> { + val baseSymbol = baseFunctionSymbols[declaration]!! + val overriddenSymbol = declarationStorage.getIrFunctionSymbol(baseSymbol) as IrSimpleFunctionSymbol + declaration.withFunction { + overriddenSymbols = listOf(overriddenSymbol) + } + } + is IrProperty -> { + val baseSymbol = basePropertySymbols[declaration]!! + declaration.withProperty { + discardAccessorsAccordingToBaseVisibility(baseSymbol) + setOverriddenSymbolsForAccessors(declarationStorage, declaration.isVar, firOverriddenSymbol = baseSymbol) + } + } + } + } + } + private fun IrProperty.discardAccessorsAccordingToBaseVisibility(baseSymbol: FirPropertySymbol) { // Do not create fake overrides for accessors if not allowed to do so, e.g., private lateinit var. if (baseSymbol.fir.getter?.allowsToHaveFakeOverride != true) { @@ -199,7 +216,7 @@ class FakeOverrideGenerator( private fun IrProperty.setOverriddenSymbolsForAccessors( declarationStorage: Fir2IrDeclarationStorage, - property: FirProperty, + isVar: Boolean, firOverriddenSymbol: FirPropertySymbol ): IrProperty { val irSymbol = declarationStorage.getIrPropertyOrFieldSymbol(firOverriddenSymbol) as? IrPropertySymbol ?: return this @@ -207,7 +224,7 @@ class FakeOverrideGenerator( getter?.apply { overriddenProperty.getter?.symbol?.let { overriddenSymbols = listOf(it) } } - if (property.isVar) { + if (isVar) { setter?.apply { overriddenProperty.setter?.symbol?.let { overriddenSymbols = listOf(it) } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt index db3c29446a8..54417c78a78 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt @@ -164,7 +164,9 @@ class Fir2IrLazyClass( } } with(fakeOverrideGenerator) { - result += getFakeOverrides(fir, processedNames) + val fakeOverrides = getFakeOverrides(fir, processedNames) + bindOverriddenSymbols(fakeOverrides) + result += fakeOverrides } // TODO: remove this check to save time for (declaration in result) { diff --git a/compiler/testData/codegen/box/classes/kt2480.kt b/compiler/testData/codegen/box/classes/kt2480.kt index 968730da672..cbeec9ce597 100644 --- a/compiler/testData/codegen/box/classes/kt2480.kt +++ b/compiler/testData/codegen/box/classes/kt2480.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR fun box() = Class().printSome() public abstract class AbstractClass { diff --git a/compiler/testData/codegen/box/jvm8/kt29242.kt b/compiler/testData/codegen/box/jvm8/kt29242.kt index 0f438ee95f9..897e051cae3 100644 --- a/compiler/testData/codegen/box/jvm8/kt29242.kt +++ b/compiler/testData/codegen/box/jvm8/kt29242.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 // See also kt33054.kt