[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 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 <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?) {
val firClassSymbol = fakeOverrideOwnerLookupTag?.toSymbol(session) as? FirClassSymbol
if (firClassSymbol != null) {
@@ -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)
}
@@ -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 <D : FirCallableDeclaration, reified S : FirCallableSymbol<D>> createFirFakeOverride(
klass: FirClass,
private inline fun <D : FirCallableDeclaration, reified S : FirCallableSymbol<D>> createFirFakeOverrideIfNeeded(
dispatchReceiverLookupTag: ConeClassLikeLookupTag,
irClass: IrClass,
originalSymbol: S,
createFakeOverrideSymbol: (firDeclaration: D, baseSymbol: S) -> S,
computeDirectOverridden: FirTypeScope.(S) -> List<S>,
scope: FirTypeScope,
): Pair<D, List<S>>? {
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 <reified S : FirCallableSymbol<*>> computeBaseSymbols(
symbol: S,
@@ -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
@@ -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<T> {
fun foo(x: T) = "x:$x"
@@ -26,4 +26,4 @@ fun box(): String {
throw Exception("test4: $test4")
return "OK"
}
}
@@ -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"
}
}