From 89b98ef7842acfd697a84681129da8d87ae5fab8 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 15 Nov 2023 17:34:47 +0200 Subject: [PATCH] [FIR2IR] Properly create FIR f/o for lazy IR f/o ```kotlin interface A { fun foo() // (1) } interface B : A { // f/o fun foo() // (2) } ``` In previous commits it was forgotten to create new FIR declarations for IR fake-overrides, which led to the situation when `IR lazy functions of `(1)` and `(2)` both contained fir of function (1) as their base declaration It seems this change fixed some cases from KT-42020 --- .../fir/backend/Fir2IrDeclarationStorage.kt | 27 ++++- .../kotlin/fir/backend/FirIrProvider.kt | 12 ++- .../generators/FakeOverrideGenerator.kt | 99 +++++++++---------- .../clashingFakeOverrideSignatures.kt | 7 +- .../box/ir/clashingFakeOverrideSignatures.kt | 6 +- .../signatureClash.kt | 4 +- 6 files changed, 87 insertions(+), 68 deletions(-) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt index 3b523d1fa3e..38e26013109 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 @@ -615,11 +615,16 @@ class Fir2IrDeclarationStorage( val symbols = createPropertySymbols(signature, property, fakeOverrideOwnerLookupTag) val irParent = findIrParent(property, fakeOverrideOwnerLookupTag) if (irParent?.isExternalParent() == true) { + val firForLazyProperty = calculateFirForLazyDeclaration( + property, fakeOverrideOwnerLookupTag, irParent, + fakeOverrideGenerator::createFirPropertyFakeOverrideIfNeeded + ) + callablesGenerator.createIrProperty( - property, + firForLazyProperty, irParent, symbols, - predefinedOrigin = property.computeExternalOrigin(), + predefinedOrigin = firForLazyProperty.computeExternalOrigin(), allowLazyDeclarationsCreation = true ).also { check(it is Fir2IrLazyProperty) @@ -991,13 +996,17 @@ class Fir2IrDeclarationStorage( if (function is FirSimpleFunction && !isLocal) { val irParent = findIrParent(function, fakeOverrideOwnerLookupTag) if (irParent?.isExternalParent() == true) { + val firForLazyFunction = calculateFirForLazyDeclaration( + function, fakeOverrideOwnerLookupTag, irParent, + fakeOverrideGenerator::createFirFunctionFakeOverrideIfNeeded + ) // Return value is not used here, because creation of IR declaration binds it to the corresponding symbol // And all we want here is to bind symbol for lazy declaration callablesGenerator.createIrFunction( - function, + firForLazyFunction, irParent, symbol, - predefinedOrigin = function.computeExternalOrigin(), + predefinedOrigin = firForLazyFunction.computeExternalOrigin(), isLocal = false, fakeOverrideOwnerLookupTag, allowLazyDeclarationsCreation = true @@ -1131,6 +1140,16 @@ class Fir2IrDeclarationStorage( return null } + private inline fun calculateFirForLazyDeclaration( + originalDeclaration: T, + fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?, + irParent: IrDeclarationParent, + createFakeOverrideIfNeeded: (T, ConeClassLikeLookupTag, IrClass) -> T? + ): T { + if (irParent !is IrClass || fakeOverrideOwnerLookupTag == null) return originalDeclaration + return createFakeOverrideIfNeeded(originalDeclaration, fakeOverrideOwnerLookupTag, irParent) ?: originalDeclaration + } + private fun generateLazyFakeOverrides(name: Name, fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?) { val firClassSymbol = fakeOverrideOwnerLookupTag?.toSymbol(session) as? FirClassSymbol if (firClassSymbol != null) { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/FirIrProvider.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/FirIrProvider.kt index 20adba597eb..9f359921b52 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/FirIrProvider.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/FirIrProvider.kt @@ -118,7 +118,11 @@ class FirIrProvider(val components: Fir2IrComponents) : IrProvider { scope.processFunctionsByName(lastName) { functionSymbol -> val dispatchReceiverClassId = (functionSymbol.fir.dispatchReceiverType as? ConeClassLikeType)?.lookupTag?.classId val function = if (dispatchReceiverClassId != null && dispatchReceiverClassId != classId) { - fakeOverrideGenerator.createFirFunctionFakeOverride(firClass, parentClass, functionSymbol, scope)!!.first + fakeOverrideGenerator.createFirFunctionFakeOverrideIfNeeded( + functionSymbol.fir, + firClass.symbol.toLookupTag(), + parentClass + )!! } else functionSymbol.fir functions.add(function) } @@ -135,7 +139,11 @@ class FirIrProvider(val components: Fir2IrComponents) : IrProvider { propertySymbol as FirPropertySymbol val dispatchReceiverClassId = (propertySymbol.fir.dispatchReceiverType as? ConeClassLikeType)?.lookupTag?.classId val property = if (dispatchReceiverClassId != null && dispatchReceiverClassId != classId) { - fakeOverrideGenerator.createFirPropertyFakeOverride(firClass, parentClass, propertySymbol, scope)!!.first + fakeOverrideGenerator.createFirPropertyFakeOverrideIfNeeded( + propertySymbol.fir, + firClass.symbol.toLookupTag(), + parentClass + )!! } else propertySymbol.fir properties.add(property) } 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 50a9f86c74e..42137f50d6b 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 @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.declarations.utils.isStatic import org.jetbrains.kotlin.fir.resolve.defaultType import org.jetbrains.kotlin.fir.resolve.isRealOwnerOf +import org.jetbrains.kotlin.fir.resolve.toFirRegularClass import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.impl.FirFakeOverrideGenerator @@ -29,6 +30,7 @@ import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.Name class FakeOverrideGenerator( @@ -314,80 +316,71 @@ class FakeOverrideGenerator( result?.add(owner) } - private inline fun > createFirFakeOverride( - klass: FirClass, + private inline fun > createFirFakeOverrideIfNeeded( + dispatchReceiverLookupTag: ConeClassLikeLookupTag, irClass: IrClass, originalSymbol: S, - createFakeOverrideSymbol: (firDeclaration: D, baseSymbol: S) -> S, - computeDirectOverridden: FirTypeScope.(S) -> List, - scope: FirTypeScope, - ): Pair>? { - val classLookupTag = klass.symbol.toLookupTag() + createFakeOverrideSymbol: (firDeclaration: D) -> S, + ): D? { val originalDeclaration = originalSymbol.fir - val baseSymbol = originalSymbol.unwrapSubstitutionAndIntersectionOverrides() as S return when { - originalSymbol.shouldHaveComputedBaseSymbolsForClass(classLookupTag) -> { - // Substitution or intersection case - // We have already a FIR declaration for such fake override - originalDeclaration to computeBaseSymbols( - originalSymbol, - computeDirectOverridden, - scope, classLookupTag - ) - } + originalSymbol.containingClassLookupTag() == dispatchReceiverLookupTag -> null + originalDeclaration.allowsToHaveFakeOverride -> { // Trivial fake override case // We've got no relevant declaration in FIR world for such a fake override in current class, thus we're creating it here - val fakeOverrideSymbol = createFakeOverrideSymbol(originalDeclaration, baseSymbol) + val fakeOverrideSymbol = createFakeOverrideSymbol(originalDeclaration) declarationStorage.saveFakeOverrideInClass(irClass, originalDeclaration, fakeOverrideSymbol.fir) - classifierStorage.preCacheTypeParameters(originalDeclaration, irClass.symbol) - fakeOverrideSymbol.fir to listOf(originalSymbol) - } - else -> { - null + fakeOverrideSymbol.fir } + + else -> null } } - internal fun createFirFunctionFakeOverride( - klass: FirClass, + internal fun createFirFunctionFakeOverrideIfNeeded( + originalFunction: FirSimpleFunction, + dispatchReceiverLookupTag: ConeClassLikeLookupTag, irClass: IrClass, - originalSymbol: FirNamedFunctionSymbol, - scope: FirTypeScope - ) = createFirFakeOverride( - klass, irClass, originalSymbol, - createFakeOverrideSymbol = { firFunction, callableSymbol -> + ): FirSimpleFunction? { + val originalSymbol = originalFunction.symbol + return createFirFakeOverrideIfNeeded( + dispatchReceiverLookupTag, irClass, originalSymbol + ) { firFunction -> + val containingClass = dispatchReceiverLookupTag.toFirRegularClass(session)!! FirFakeOverrideGenerator.createSubstitutionOverrideFunction( - session, callableSymbol, firFunction, - derivedClassLookupTag = klass.symbol.toLookupTag(), - newDispatchReceiverType = klass.defaultType(), + session, + FirNamedFunctionSymbol(CallableId(containingClass.symbol.classId, originalSymbol.callableId.callableName)), + firFunction, + derivedClassLookupTag = dispatchReceiverLookupTag, + newDispatchReceiverType = containingClass.defaultType(), origin = FirDeclarationOrigin.SubstitutionOverride.DeclarationSite, - isExpect = (klass as? FirRegularClass)?.isExpect == true || firFunction.isExpect + isExpect = containingClass.isExpect || firFunction.isExpect ) - }, - computeDirectOverridden = FirTypeScope::getDirectOverriddenFunctions, - scope - ) + } + } - internal fun createFirPropertyFakeOverride( - klass: FirClass, + internal fun createFirPropertyFakeOverrideIfNeeded( + originalProperty: FirProperty, + dispatchReceiverLookupTag: ConeClassLikeLookupTag, irClass: IrClass, - originalSymbol: FirPropertySymbol, - scope: FirTypeScope - ) = createFirFakeOverride( - klass, irClass, originalSymbol, - createFakeOverrideSymbol = { firProperty, callableSymbol -> + ): FirProperty? { + val originalSymbol = originalProperty.symbol + return createFirFakeOverrideIfNeeded( + dispatchReceiverLookupTag, irClass, originalSymbol + ) { firProperty -> + val containingClass = dispatchReceiverLookupTag.toFirRegularClass(session)!! FirFakeOverrideGenerator.createSubstitutionOverrideProperty( - session, callableSymbol, firProperty, - derivedClassLookupTag = klass.symbol.toLookupTag(), - newDispatchReceiverType = klass.defaultType(), + session, + FirPropertySymbol(CallableId(containingClass.symbol.classId, originalSymbol.callableId.callableName)), + firProperty, + derivedClassLookupTag = dispatchReceiverLookupTag, + newDispatchReceiverType = containingClass.defaultType(), origin = FirDeclarationOrigin.SubstitutionOverride.DeclarationSite, - isExpect = (klass as? FirRegularClass)?.isExpect == true || firProperty.isExpect + isExpect = containingClass.isExpect || firProperty.isExpect ) - }, - computeDirectOverridden = FirTypeScope::getDirectOverriddenProperties, - scope - ) + } + } private inline fun > computeBaseSymbols( symbol: S, diff --git a/compiler/testData/codegen/box/compileKotlinAgainstKotlin/clashingFakeOverrideSignatures.kt b/compiler/testData/codegen/box/compileKotlinAgainstKotlin/clashingFakeOverrideSignatures.kt index 5f97608588d..280446679be 100644 --- a/compiler/testData/codegen/box/compileKotlinAgainstKotlin/clashingFakeOverrideSignatures.kt +++ b/compiler/testData/codegen/box/compileKotlinAgainstKotlin/clashingFakeOverrideSignatures.kt @@ -1,7 +1,8 @@ -// IGNORE_BACKEND_K2: JVM_IR, JS_IR -// KT-59609 +// IGNORE_BACKEND_K2: JS_IR // IGNORE_BACKEND: NATIVE -// FIR status: Validation failed. TODO decide if we want to fix KT-42020 for FIR as well +// IGNORE_CODEGEN_WITH_IR_FAKE_OVERRIDE_GENERATION +// Reason: KT-42020 + // MODULE: lib // FILE: a.kt package a diff --git a/compiler/testData/codegen/box/ir/clashingFakeOverrideSignatures.kt b/compiler/testData/codegen/box/ir/clashingFakeOverrideSignatures.kt index 779d86f762b..3738f62137c 100644 --- a/compiler/testData/codegen/box/ir/clashingFakeOverrideSignatures.kt +++ b/compiler/testData/codegen/box/ir/clashingFakeOverrideSignatures.kt @@ -1,6 +1,6 @@ // TARGET_BACKEND: JVM -// IGNORE_BACKEND_K2: JVM_IR, JS_IR -// FIR status: validation failed. TODO decide if we want to fix KT-42020 for FIR as well +// IGNORE_CODEGEN_WITH_IR_FAKE_OVERRIDE_GENERATION +// Reason: KT-42020 open class Base { fun foo(x: T) = "x:$x" @@ -26,4 +26,4 @@ fun box(): String { throw Exception("test4: $test4") return "OK" -} \ No newline at end of file +} diff --git a/compiler/testData/codegen/box/ir/serializationRegressions/signatureClash.kt b/compiler/testData/codegen/box/ir/serializationRegressions/signatureClash.kt index 7b2054a39d6..55d7962440b 100644 --- a/compiler/testData/codegen/box/ir/serializationRegressions/signatureClash.kt +++ b/compiler/testData/codegen/box/ir/serializationRegressions/signatureClash.kt @@ -7,8 +7,6 @@ // IGNORE_BACKEND: JS // IGNORE_BACKEND_K2: NATIVE, JS_IR -// FIR status: validation failed. TODO decide if we want to fix KT-42020 for FIR as well -// IGNORE_BACKEND_K2: JVM_IR // MODULE: lib // FILE: lib.kt @@ -31,4 +29,4 @@ fun box(): String { if (foo24 != "p2:24") return "FAIL2: foo24=$foo24" return "OK" -} \ No newline at end of file +}