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 fe1adc73316..da481d1d150 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 @@ -405,17 +405,32 @@ class Fir2IrDeclarationStorage( if (function is FirSimpleFunction) getCachedIrFunction(function) else localStorage.getLocalFunction(function) + fun getCachedIrFunction(function: FirSimpleFunction): IrSimpleFunction? { + return if (function.visibility == Visibilities.Local) { + localStorage.getLocalFunction(function) + } else { + functionCache[function] + } + } + fun getCachedIrFunction( function: FirSimpleFunction, - signatureCalculator: (FirSimpleFunction) -> IdSignature? = { null } + dispatchReceiverLookupTag: ConeClassLikeLookupTag?, + signatureCalculator: (FirSimpleFunction) -> IdSignature? ): IrSimpleFunction? { return if (function.visibility == Visibilities.Local) { localStorage.getLocalFunction(function) } else { - functionCache[function] ?: signatureCalculator(function)?.let { signature -> + val isFakeOverride = dispatchReceiverLookupTag != null && + dispatchReceiverLookupTag !is ConeClassLookupTagWithFixedSymbol && + dispatchReceiverLookupTag != function.containingClass() + val cached = if (isFakeOverride) null else functionCache[function] + cached ?: signatureCalculator(function)?.let { signature -> symbolTable.referenceSimpleFunctionIfAny(signature)?.let { irFunctionSymbol -> val irFunction = irFunctionSymbol.owner - functionCache[function] = irFunction + if (!isFakeOverride) { + functionCache[function] = irFunction + } irFunction } } @@ -874,14 +889,23 @@ class Fir2IrDeclarationStorage( } } + fun getCachedIrProperty(property: FirProperty): IrProperty? = propertyCache[property] + fun getCachedIrProperty( property: FirProperty, - signatureCalculator: (FirProperty) -> IdSignature? = { null } + dispatchReceiverLookupTag: ConeClassLikeLookupTag?, + signatureCalculator: (FirProperty) -> IdSignature? ): IrProperty? { - return propertyCache[property] ?: signatureCalculator(property)?.let { signature -> + val isFakeOverride = dispatchReceiverLookupTag != null && + dispatchReceiverLookupTag !is ConeClassLookupTagWithFixedSymbol && + dispatchReceiverLookupTag != property.containingClass() + val cached = if (isFakeOverride) null else propertyCache[property] + return cached ?: signatureCalculator(property)?.let { signature -> symbolTable.referencePropertyIfAny(signature)?.let { irPropertySymbol -> val irProperty = irPropertySymbol.owner - propertyCache[property] = irProperty + if (!isFakeOverride) { + propertyCache[property] = irProperty + } irProperty } } @@ -1075,7 +1099,8 @@ class Fir2IrDeclarationStorage( val fir = firConstructorSymbol.fir return getIrCallableSymbol( firConstructorSymbol, - getCachedIrDeclaration = ::getCachedIrConstructor, + dispatchReceiverLookupTag = null, + getCachedIrDeclaration = { constructor: FirConstructor, _, calculator -> getCachedIrConstructor(constructor, calculator) }, createIrDeclaration = { parent, origin -> createIrConstructor(fir, parent as IrClass, predefinedOrigin = origin) }, createIrLazyDeclaration = { signature, lazyParent, declarationOrigin -> val symbol = Fir2IrConstructorSymbol(signature) @@ -1109,8 +1134,13 @@ class Fir2IrDeclarationStorage( createIrFunction(fir, irParent, predefinedOrigin = declarationOrigin).symbol } is FirSimpleFunction -> { + val unmatchedReceiver = dispatchReceiverLookupTag != firFunctionSymbol.containingClass() + if (unmatchedReceiver) { + generateLazyFakeOverrides(fir.name, dispatchReceiverLookupTag) + } val originalSymbol = getIrCallableSymbol( firFunctionSymbol, + dispatchReceiverLookupTag, getCachedIrDeclaration = ::getCachedIrFunction, createIrDeclaration = { parent, origin -> createIrFunction(fir, parent, predefinedOrigin = origin) }, createIrLazyDeclaration = { signature, lazyParent, declarationOrigin -> @@ -1135,14 +1165,14 @@ class Fir2IrDeclarationStorage( irFunction } ) as IrFunctionSymbol - if (dispatchReceiverLookupTag != null && dispatchReceiverLookupTag != firFunctionSymbol.containingClass()) { + if (dispatchReceiverLookupTag is ConeClassLookupTagWithFixedSymbol && unmatchedReceiver) { val dispatchReceiverIrClass = classifierStorage.getIrClassSymbol(dispatchReceiverLookupTag.toSymbol(session) as FirClassSymbol).owner dispatchReceiverIrClass.declarations.find { it is IrSimpleFunction && it.isFakeOverride && it.name == fir.name && it.overrides(originalSymbol.owner as IrSimpleFunction) }?.symbol as? IrFunctionSymbol - ?: originalSymbol // Fallback (normally we should not be here, but f/o are bound too late) + ?: originalSymbol // Fallback (normally we should not be here, but f/o are bound too late for local classes) } else { originalSymbol } @@ -1162,8 +1192,13 @@ class Fir2IrDeclarationStorage( if (fir.isLocal) { return localStorage.getDelegatedProperty(fir)?.symbol ?: getIrVariableSymbol(fir) } + val unmatchedReceiver = dispatchReceiverLookupTag != firPropertySymbol.containingClass() + if (unmatchedReceiver) { + generateLazyFakeOverrides(fir.name, dispatchReceiverLookupTag) + } val originalSymbol = getIrCallableSymbol( firPropertySymbol, + dispatchReceiverLookupTag, getCachedIrDeclaration = ::getCachedIrProperty, createIrDeclaration = { parent, origin -> createIrProperty(fir, parent, predefinedOrigin = origin) }, createIrLazyDeclaration = { signature, lazyParent, declarationOrigin -> @@ -1185,33 +1220,46 @@ class Fir2IrDeclarationStorage( return symbol } ) - return if (dispatchReceiverLookupTag != null && dispatchReceiverLookupTag != firPropertySymbol.containingClass()) { + return if (dispatchReceiverLookupTag is ConeClassLookupTagWithFixedSymbol && + dispatchReceiverLookupTag != firPropertySymbol.containingClass() + ) { val dispatchReceiverIrClass = classifierStorage.getIrClassSymbol(dispatchReceiverLookupTag.toSymbol(session) as FirClassSymbol).owner dispatchReceiverIrClass.declarations.find { it is IrProperty && it.isFakeOverride && it.name == fir.name && it.overrides(originalSymbol.owner as IrProperty) }?.symbol as? IrPropertySymbol - ?: originalSymbol // Fallback (normally we should not be here, but f/o are bound too late) + ?: originalSymbol // Fallback (normally we should not be here, but f/o are bound too late for local classes) } else { originalSymbol } } + private fun generateLazyFakeOverrides(name: Name, dispatchReceiverLookupTag: ConeClassLikeLookupTag?) { + val firClassSymbol = dispatchReceiverLookupTag?.toSymbol(session) as? FirClassSymbol + if (firClassSymbol != null) { + val irClass = classifierStorage.getIrClassSymbol(firClassSymbol).owner + if (irClass is Fir2IrLazyClass) { + irClass.getFakeOverridesByName(name) + } + } + } + private inline fun < reified FS : FirCallableSymbol<*>, reified F : FirCallableDeclaration, I : IrSymbolOwner, > getIrCallableSymbol( firSymbol: FS, - getCachedIrDeclaration: (F, (F) -> IdSignature?) -> I?, + dispatchReceiverLookupTag: ConeClassLikeLookupTag?, + getCachedIrDeclaration: (F, ConeClassLikeLookupTag?, (F) -> IdSignature?) -> I?, createIrDeclaration: (IrDeclarationParent?, IrDeclarationOrigin) -> I, createIrLazyDeclaration: (IdSignature, Fir2IrLazyClass, IrDeclarationOrigin) -> I, ): IrSymbol { val fir = firSymbol.fir as F val irParent by lazy { findIrParent(fir) } - val signature by lazy { signatureComposer.composeSignature(fir) } + val signature by lazy { signatureComposer.composeSignature(fir, dispatchReceiverLookupTag) } synchronized(symbolTable.lock) { - getCachedIrDeclaration(fir) { + getCachedIrDeclaration(fir, dispatchReceiverLookupTag) { // Parent calculation provokes declaration calculation for some members from IrBuiltIns @Suppress("UNUSED_EXPRESSION") irParent signature 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 7a99ecc0b9d..e343a404bad 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 @@ -184,7 +184,7 @@ class FakeOverrideGenerator( irClass: IrClass, isLocal: Boolean, originalSymbol: FirCallableSymbol<*>, - cachedIrDeclaration: (D, (D) -> IdSignature?) -> I?, + cachedIrDeclaration: (D, ConeClassLikeLookupTag?, (D) -> IdSignature?) -> I?, createIrDeclaration: (D, irParent: IrClass, thisReceiverOwner: IrClass?, origin: IrDeclarationOrigin, isLocal: Boolean) -> I, createFakeOverrideSymbol: (D, S) -> S, baseSymbols: MutableMap>, @@ -227,7 +227,7 @@ class FakeOverrideGenerator( return } } - val irDeclaration = cachedIrDeclaration(fakeOverrideFirDeclaration) { + val irDeclaration = cachedIrDeclaration(fakeOverrideFirDeclaration, null) { // Sometimes we can have clashing here when FIR substitution/intersection override // have the same signature. // Now we avoid this problem by signature caching, diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/equalsIsCalledByInlineClass.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/equalsIsCalledByInlineClass.kt index 9eeda4f2f75..ace25a5efb9 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/equalsIsCalledByInlineClass.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/equalsIsCalledByInlineClass.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +InlineClasses -// IGNORE_BACKEND_FIR: JVM_IR // FILE: Z.kt inline class Z(val x: Int) diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/hashCodeIsCalledByInlineClass.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/hashCodeIsCalledByInlineClass.kt index 8a0834ec164..0f058373224 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/hashCodeIsCalledByInlineClass.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/hashCodeIsCalledByInlineClass.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +InlineClasses -// IGNORE_BACKEND_FIR: JVM_IR // FILE: Z.kt inline class Z(val x: Int) diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/toStringOfInlineClassValue.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/toStringOfInlineClassValue.kt index ff348cfa77d..7798e2ee988 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/toStringOfInlineClassValue.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/toStringOfInlineClassValue.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +InlineClasses -// IGNORE_BACKEND_FIR: JVM_IR // FILE: Z.kt inline class Z(val x: Int) diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/toStringOfReferenceInlineClassValue.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/toStringOfReferenceInlineClassValue.kt index 08ae4afa45b..7dcb0481cff 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/toStringOfReferenceInlineClassValue.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/toStringOfReferenceInlineClassValue.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +InlineClasses -// IGNORE_BACKEND_FIR: JVM_IR // Completely incorrect bytecode - see `box/inlineClasses/toStringOfUnboxedNullable.kt` // IGNORE_BACKEND: JVM