[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
This commit is contained in:
Dmitriy Novozhilov
2023-11-15 17:34:47 +02:00
committed by Space Team
parent 8ebb412705
commit 89b98ef784
6 changed files with 87 additions and 68 deletions
@@ -615,11 +615,16 @@ class Fir2IrDeclarationStorage(
val symbols = createPropertySymbols(signature, property, fakeOverrideOwnerLookupTag) val symbols = createPropertySymbols(signature, property, fakeOverrideOwnerLookupTag)
val irParent = findIrParent(property, fakeOverrideOwnerLookupTag) val irParent = findIrParent(property, fakeOverrideOwnerLookupTag)
if (irParent?.isExternalParent() == true) { if (irParent?.isExternalParent() == true) {
val firForLazyProperty = calculateFirForLazyDeclaration(
property, fakeOverrideOwnerLookupTag, irParent,
fakeOverrideGenerator::createFirPropertyFakeOverrideIfNeeded
)
callablesGenerator.createIrProperty( callablesGenerator.createIrProperty(
property, firForLazyProperty,
irParent, irParent,
symbols, symbols,
predefinedOrigin = property.computeExternalOrigin(), predefinedOrigin = firForLazyProperty.computeExternalOrigin(),
allowLazyDeclarationsCreation = true allowLazyDeclarationsCreation = true
).also { ).also {
check(it is Fir2IrLazyProperty) check(it is Fir2IrLazyProperty)
@@ -991,13 +996,17 @@ class Fir2IrDeclarationStorage(
if (function is FirSimpleFunction && !isLocal) { if (function is FirSimpleFunction && !isLocal) {
val irParent = findIrParent(function, fakeOverrideOwnerLookupTag) val irParent = findIrParent(function, fakeOverrideOwnerLookupTag)
if (irParent?.isExternalParent() == true) { 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 // 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 // And all we want here is to bind symbol for lazy declaration
callablesGenerator.createIrFunction( callablesGenerator.createIrFunction(
function, firForLazyFunction,
irParent, irParent,
symbol, symbol,
predefinedOrigin = function.computeExternalOrigin(), predefinedOrigin = firForLazyFunction.computeExternalOrigin(),
isLocal = false, isLocal = false,
fakeOverrideOwnerLookupTag, fakeOverrideOwnerLookupTag,
allowLazyDeclarationsCreation = true allowLazyDeclarationsCreation = true
@@ -1131,6 +1140,16 @@ class Fir2IrDeclarationStorage(
return null return null
} }
private inline fun <T : FirCallableDeclaration> 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?) { private fun generateLazyFakeOverrides(name: Name, fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?) {
val firClassSymbol = fakeOverrideOwnerLookupTag?.toSymbol(session) as? FirClassSymbol val firClassSymbol = fakeOverrideOwnerLookupTag?.toSymbol(session) as? FirClassSymbol
if (firClassSymbol != null) { if (firClassSymbol != null) {
@@ -118,7 +118,11 @@ class FirIrProvider(val components: Fir2IrComponents) : IrProvider {
scope.processFunctionsByName(lastName) { functionSymbol -> scope.processFunctionsByName(lastName) { functionSymbol ->
val dispatchReceiverClassId = (functionSymbol.fir.dispatchReceiverType as? ConeClassLikeType)?.lookupTag?.classId val dispatchReceiverClassId = (functionSymbol.fir.dispatchReceiverType as? ConeClassLikeType)?.lookupTag?.classId
val function = if (dispatchReceiverClassId != null && dispatchReceiverClassId != 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 } else functionSymbol.fir
functions.add(function) functions.add(function)
} }
@@ -135,7 +139,11 @@ class FirIrProvider(val components: Fir2IrComponents) : IrProvider {
propertySymbol as FirPropertySymbol propertySymbol as FirPropertySymbol
val dispatchReceiverClassId = (propertySymbol.fir.dispatchReceiverType as? ConeClassLikeType)?.lookupTag?.classId val dispatchReceiverClassId = (propertySymbol.fir.dispatchReceiverType as? ConeClassLikeType)?.lookupTag?.classId
val property = if (dispatchReceiverClassId != null && dispatchReceiverClassId != 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 } else propertySymbol.fir
properties.add(property) properties.add(property)
} }
@@ -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.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.resolve.defaultType import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.isRealOwnerOf 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.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.scopes.impl.FirFakeOverrideGenerator 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.types.*
import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
class FakeOverrideGenerator( class FakeOverrideGenerator(
@@ -314,80 +316,71 @@ class FakeOverrideGenerator(
result?.add(owner) result?.add(owner)
} }
private inline fun <D : FirCallableDeclaration, reified S : FirCallableSymbol<D>> createFirFakeOverride( private inline fun <D : FirCallableDeclaration, reified S : FirCallableSymbol<D>> createFirFakeOverrideIfNeeded(
klass: FirClass, dispatchReceiverLookupTag: ConeClassLikeLookupTag,
irClass: IrClass, irClass: IrClass,
originalSymbol: S, originalSymbol: S,
createFakeOverrideSymbol: (firDeclaration: D, baseSymbol: S) -> S, createFakeOverrideSymbol: (firDeclaration: D) -> S,
computeDirectOverridden: FirTypeScope.(S) -> List<S>, ): D? {
scope: FirTypeScope,
): Pair<D, List<S>>? {
val classLookupTag = klass.symbol.toLookupTag()
val originalDeclaration = originalSymbol.fir val originalDeclaration = originalSymbol.fir
val baseSymbol = originalSymbol.unwrapSubstitutionAndIntersectionOverrides() as S
return when { return when {
originalSymbol.shouldHaveComputedBaseSymbolsForClass(classLookupTag) -> { originalSymbol.containingClassLookupTag() == dispatchReceiverLookupTag -> null
// Substitution or intersection case
// We have already a FIR declaration for such fake override
originalDeclaration to computeBaseSymbols(
originalSymbol,
computeDirectOverridden,
scope, classLookupTag
)
}
originalDeclaration.allowsToHaveFakeOverride -> { originalDeclaration.allowsToHaveFakeOverride -> {
// Trivial fake override case // 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 // 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) declarationStorage.saveFakeOverrideInClass(irClass, originalDeclaration, fakeOverrideSymbol.fir)
classifierStorage.preCacheTypeParameters(originalDeclaration, irClass.symbol) fakeOverrideSymbol.fir
fakeOverrideSymbol.fir to listOf(originalSymbol)
}
else -> {
null
} }
else -> null
} }
} }
internal fun createFirFunctionFakeOverride( internal fun createFirFunctionFakeOverrideIfNeeded(
klass: FirClass, originalFunction: FirSimpleFunction,
dispatchReceiverLookupTag: ConeClassLikeLookupTag,
irClass: IrClass, irClass: IrClass,
originalSymbol: FirNamedFunctionSymbol, ): FirSimpleFunction? {
scope: FirTypeScope val originalSymbol = originalFunction.symbol
) = createFirFakeOverride( return createFirFakeOverrideIfNeeded(
klass, irClass, originalSymbol, dispatchReceiverLookupTag, irClass, originalSymbol
createFakeOverrideSymbol = { firFunction, callableSymbol -> ) { firFunction ->
val containingClass = dispatchReceiverLookupTag.toFirRegularClass(session)!!
FirFakeOverrideGenerator.createSubstitutionOverrideFunction( FirFakeOverrideGenerator.createSubstitutionOverrideFunction(
session, callableSymbol, firFunction, session,
derivedClassLookupTag = klass.symbol.toLookupTag(), FirNamedFunctionSymbol(CallableId(containingClass.symbol.classId, originalSymbol.callableId.callableName)),
newDispatchReceiverType = klass.defaultType(), firFunction,
derivedClassLookupTag = dispatchReceiverLookupTag,
newDispatchReceiverType = containingClass.defaultType(),
origin = FirDeclarationOrigin.SubstitutionOverride.DeclarationSite, origin = FirDeclarationOrigin.SubstitutionOverride.DeclarationSite,
isExpect = (klass as? FirRegularClass)?.isExpect == true || firFunction.isExpect isExpect = containingClass.isExpect || firFunction.isExpect
) )
}, }
computeDirectOverridden = FirTypeScope::getDirectOverriddenFunctions, }
scope
)
internal fun createFirPropertyFakeOverride( internal fun createFirPropertyFakeOverrideIfNeeded(
klass: FirClass, originalProperty: FirProperty,
dispatchReceiverLookupTag: ConeClassLikeLookupTag,
irClass: IrClass, irClass: IrClass,
originalSymbol: FirPropertySymbol, ): FirProperty? {
scope: FirTypeScope val originalSymbol = originalProperty.symbol
) = createFirFakeOverride( return createFirFakeOverrideIfNeeded(
klass, irClass, originalSymbol, dispatchReceiverLookupTag, irClass, originalSymbol
createFakeOverrideSymbol = { firProperty, callableSymbol -> ) { firProperty ->
val containingClass = dispatchReceiverLookupTag.toFirRegularClass(session)!!
FirFakeOverrideGenerator.createSubstitutionOverrideProperty( FirFakeOverrideGenerator.createSubstitutionOverrideProperty(
session, callableSymbol, firProperty, session,
derivedClassLookupTag = klass.symbol.toLookupTag(), FirPropertySymbol(CallableId(containingClass.symbol.classId, originalSymbol.callableId.callableName)),
newDispatchReceiverType = klass.defaultType(), firProperty,
derivedClassLookupTag = dispatchReceiverLookupTag,
newDispatchReceiverType = containingClass.defaultType(),
origin = FirDeclarationOrigin.SubstitutionOverride.DeclarationSite, origin = FirDeclarationOrigin.SubstitutionOverride.DeclarationSite,
isExpect = (klass as? FirRegularClass)?.isExpect == true || firProperty.isExpect isExpect = containingClass.isExpect || firProperty.isExpect
) )
}, }
computeDirectOverridden = FirTypeScope::getDirectOverriddenProperties, }
scope
)
private inline fun <reified S : FirCallableSymbol<*>> computeBaseSymbols( private inline fun <reified S : FirCallableSymbol<*>> computeBaseSymbols(
symbol: S, symbol: S,
@@ -1,7 +1,8 @@
// IGNORE_BACKEND_K2: JVM_IR, JS_IR // IGNORE_BACKEND_K2: JS_IR
// KT-59609
// IGNORE_BACKEND: NATIVE // 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 // MODULE: lib
// FILE: a.kt // FILE: a.kt
package a package a
@@ -1,6 +1,6 @@
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// IGNORE_BACKEND_K2: JVM_IR, JS_IR // IGNORE_CODEGEN_WITH_IR_FAKE_OVERRIDE_GENERATION
// FIR status: validation failed. TODO decide if we want to fix KT-42020 for FIR as well // Reason: KT-42020
open class Base<T> { open class Base<T> {
fun foo(x: T) = "x:$x" fun foo(x: T) = "x:$x"
@@ -26,4 +26,4 @@ fun box(): String {
throw Exception("test4: $test4") throw Exception("test4: $test4")
return "OK" return "OK"
} }
@@ -7,8 +7,6 @@
// IGNORE_BACKEND: JS // IGNORE_BACKEND: JS
// IGNORE_BACKEND_K2: NATIVE, JS_IR // 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 // MODULE: lib
// FILE: lib.kt // FILE: lib.kt
@@ -31,4 +29,4 @@ fun box(): String {
if (foo24 != "p2:24") return "FAIL2: foo24=$foo24" if (foo24 != "p2:24") return "FAIL2: foo24=$foo24"
return "OK" return "OK"
} }