diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConversionScope.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConversionScope.kt index 302c333b3db..06c56ba98ec 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConversionScope.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConversionScope.kt @@ -5,9 +5,7 @@ package org.jetbrains.kotlin.fir.backend -import org.jetbrains.kotlin.fir.declarations.FirClass -import org.jetbrains.kotlin.fir.declarations.FirConstructor -import org.jetbrains.kotlin.fir.declarations.FirFunction +import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.FirReturnExpression import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.util.parentClassOrNull @@ -99,10 +97,9 @@ class Fir2IrConversionScope { fun returnTarget(expression: FirReturnExpression, declarationStorage: Fir2IrDeclarationStorage): IrFunction { val firTarget = expression.target.labeledElement val irTarget = (firTarget as? FirFunction)?.let { - if (it is FirConstructor) { - declarationStorage.getCachedIrConstructor(it) - } else { - declarationStorage.getCachedIrFunction(it) + when (it) { + is FirConstructor -> declarationStorage.getCachedIrConstructor(it) + else -> declarationStorage.getCachedIrFunction(it) } } for (potentialTarget in functionStack.asReversed()) { 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 70f27f869b2..96143f9d7fd 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 @@ -297,9 +297,7 @@ class Fir2IrConverter( // Necessary call to generate built-in IR classes externalDependenciesGenerator.generateUnboundSymbolsAsDependencies() classifierStorage.preCacheBuiltinClasses() - val fakeOverrideGenerator = FakeOverrideGenerator( - session, scopeSession, classifierStorage, declarationStorage, conversionScope - ) + val fakeOverrideGenerator = FakeOverrideGenerator(components, conversionScope) components.fakeOverrideGenerator = fakeOverrideGenerator val callGenerator = CallAndReferenceGenerator(components, fir2irVisitor, conversionScope) components.callGenerator = callGenerator 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 a76aae82efe..46d100627dc 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 @@ -364,11 +364,24 @@ class Fir2IrDeclarationStorage( return this } - fun getCachedIrFunction(function: FirFunction<*>): IrSimpleFunction? { - return if (function !is FirSimpleFunction || function.visibility == Visibilities.Local) { + fun getCachedIrFunction(function: FirFunction<*>): IrSimpleFunction? = + if (function is FirSimpleFunction) getCachedIrFunction(function) + else localStorage.getLocalFunction(function) + + fun getCachedIrFunction( + function: FirSimpleFunction, + signatureCalculator: (FirSimpleFunction) -> IdSignature? = { null } + ): IrSimpleFunction? { + return if (function.visibility == Visibilities.Local) { localStorage.getLocalFunction(function) } else { - functionCache[function] + functionCache[function] ?: signatureCalculator(function)?.let { signature -> + symbolTable.referenceSimpleFunctionIfAny(signature)?.let { irFunctionSymbol -> + val irFunction = irFunctionSymbol.owner + functionCache[function] = irFunction + irFunction + } + } } } @@ -394,7 +407,7 @@ class Fir2IrDeclarationStorage( } fun getOrCreateIrFunction( - function: FirFunction<*>, + function: FirSimpleFunction, irParent: IrDeclarationParent?, isLocal: Boolean = false, ): IrSimpleFunction { @@ -792,7 +805,18 @@ class Fir2IrDeclarationStorage( } } - fun getCachedIrProperty(property: FirProperty): IrProperty? = propertyCache[property] + fun getCachedIrProperty( + property: FirProperty, + signatureCalculator: (FirProperty) -> IdSignature? = { null } + ): IrProperty? { + return propertyCache[property] ?: signatureCalculator(property)?.let { signature -> + symbolTable.referencePropertyIfAny(signature)?.let { irPropertySymbol -> + val irProperty = irPropertySymbol.owner + propertyCache[property] = irProperty + irProperty + } + } + } internal fun cacheDelegatedProperty(property: FirProperty, irProperty: IrProperty) { propertyCache[property] = irProperty @@ -808,11 +832,6 @@ class Fir2IrDeclarationStorage( return irField } - private fun getFirClassByFqName(classId: ClassId): FirClass<*>? { - val declaration = firSymbolProvider.getClassLikeSymbolByFqName(classId) - return declaration?.fir as? FirClass<*> - } - private fun createIrField( field: FirField, origin: IrDeclarationOrigin = IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB @@ -1012,33 +1031,43 @@ class Fir2IrDeclarationStorage( fun getIrFunctionSymbol(firFunctionSymbol: FirFunctionSymbol<*>): IrFunctionSymbol { return when (val firDeclaration = firFunctionSymbol.fir) { - is FirSimpleFunction, is FirAnonymousFunction -> { + is FirAnonymousFunction -> { getCachedIrFunction(firDeclaration)?.let { return it.symbol } - val signature = signatureComposer.composeSignature(firDeclaration) val irParent = findIrParent(firDeclaration) val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED + val declarationOrigin = computeDeclarationOrigin(firFunctionSymbol, parentOrigin, irParent) + createIrFunction(firDeclaration, irParent, origin = declarationOrigin).apply { + setAndModifyParent(irParent) + }.symbol + } + is FirSimpleFunction -> { + val irParent by lazy { findIrParent(firDeclaration) } + getCachedIrFunction(firDeclaration) { + // Parent calculation provokes function calculation for some members from IrBuiltIns + @Suppress("UNUSED_EXPRESSION") irParent + signatureComposer.composeSignature(it) + }?.let { return it.symbol } + val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED - if (signature != null) { - symbolTable.referenceSimpleFunctionIfAny(signature)?.let { irFunctionSymbol -> - val irFunction = irFunctionSymbol.owner - functionCache[firDeclaration] = irFunction - return irFunctionSymbol + // TODO: package fragment members (?) + val parent = irParent + if (parent is Fir2IrLazyClass) { + assert(parentOrigin != IrDeclarationOrigin.DEFINED) { + "Should not have reference to public API uncached simple function from source code" } - // TODO: package fragment members (?) - if (firDeclaration is FirSimpleFunction && irParent is Fir2IrLazyClass) { - assert(parentOrigin != IrDeclarationOrigin.DEFINED) { - "Should not have reference to public API uncached simple function from source code" - } + val signature = signatureComposer.composeSignature(firDeclaration) + if (signature != null) { val symbol = Fir2IrSimpleFunctionSymbol(signature, firDeclaration.containerSource) val irFunction = firDeclaration.convertWithOffsets { startOffset, endOffset -> symbolTable.declareSimpleFunction(signature, { symbol }) { val isFakeOverride = firFunctionSymbol is FirNamedFunctionSymbol && firFunctionSymbol.fir.isSubstitutionOverride && - firFunctionSymbol.dispatchReceiverClassOrNull() != firFunctionSymbol.originalForSubstitutionOverride?.dispatchReceiverClassOrNull() + firFunctionSymbol.dispatchReceiverClassOrNull() != + firFunctionSymbol.originalForSubstitutionOverride?.dispatchReceiverClassOrNull() Fir2IrLazySimpleFunction( - components, startOffset, endOffset, parentOrigin, firDeclaration, irParent.fir, symbol, isFakeOverride + components, startOffset, endOffset, parentOrigin, firDeclaration, parent.fir, symbol, isFakeOverride ).apply { - parent = irParent + this.parent = parent } } } @@ -1078,24 +1107,24 @@ class Fir2IrDeclarationStorage( if (fir.isLocal) { return localStorage.getDelegatedProperty(fir)?.symbol ?: getIrVariableSymbol(fir) } - propertyCache[fir]?.let { return it.symbol } - val signature = signatureComposer.composeSignature(fir) - val irParent = findIrParent(fir) + val irParent by lazy { findIrParent(fir) } + getCachedIrProperty(fir) { + // Parent calculation provokes property calculation for some members from IrBuiltIns + @Suppress("UNUSED_EXPRESSION") irParent + signatureComposer.composeSignature(it) + }?.let { return it.symbol } val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED // TODO: Use computeDeclarationOrigin(firPropertySymbol, parentOrigin) // Currently many backend tests are failing val declarationOrigin = parentOrigin - if (signature != null) { - symbolTable.referencePropertyIfAny(signature)?.let { irPropertySymbol -> - val irProperty = irPropertySymbol.owner - propertyCache[fir] = irProperty - return irPropertySymbol + // TODO: package fragment members (?) + val parent = irParent + if (parent is Fir2IrLazyClass) { + assert(parentOrigin != IrDeclarationOrigin.DEFINED) { + "Should not have reference to public API uncached property from source code" } - // TODO: package fragment members (?) - if (irParent is Fir2IrLazyClass) { - assert(parentOrigin != IrDeclarationOrigin.DEFINED) { - "Should not have reference to public API uncached property from source code" - } + val signature = signatureComposer.composeSignature(fir) + if (signature != null) { val symbol = Fir2IrPropertySymbol(signature, fir.containerSource) val irProperty = fir.convertWithOffsets { startOffset, endOffset -> symbolTable.declareProperty(signature, { symbol }) { @@ -1103,9 +1132,9 @@ class Fir2IrDeclarationStorage( firPropertySymbol.fir.isSubstitutionOverride && firPropertySymbol.dispatchReceiverClassOrNull() != firPropertySymbol.originalForSubstitutionOverride?.dispatchReceiverClassOrNull() Fir2IrLazyProperty( - components, startOffset, endOffset, declarationOrigin, fir, irParent.fir, symbol, isFakeOverride + components, startOffset, endOffset, declarationOrigin, fir, parent.fir, symbol, isFakeOverride ).apply { - parent = irParent + this.parent = parent } } } 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 ca15dcb9add..aeafa184aad 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 @@ -9,7 +9,6 @@ import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.backend.* import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.defaultType import org.jetbrains.kotlin.fir.scopes.FirTypeScope import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenFunctions @@ -28,15 +27,13 @@ import org.jetbrains.kotlin.ir.types.IrErrorType import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrTypeProjection +import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities class FakeOverrideGenerator( - private val session: FirSession, - private val scopeSession: ScopeSession, - private val classifierStorage: Fir2IrClassifierStorage, - private val declarationStorage: Fir2IrDeclarationStorage, + private val components: Fir2IrComponents, private val conversionScope: Fir2IrConversionScope -) { +) : Fir2IrComponents by components { private val baseFunctionSymbols = mutableMapOf>() private val basePropertySymbols = mutableMapOf>() @@ -134,7 +131,7 @@ class FakeOverrideGenerator( irClass: IrClass, isLocal: Boolean, originalSymbol: FirCallableSymbol<*>, - cachedIrDeclaration: (D) -> I?, + cachedIrDeclaration: (D, (D) -> IdSignature?) -> I?, createIrDeclaration: (D, irParent: IrClass, thisReceiverOwner: IrClass?, origin: IrDeclarationOrigin, isLocal: Boolean) -> I, createFakeOverrideSymbol: (D, S) -> S, baseSymbols: MutableMap>, @@ -156,7 +153,13 @@ class FakeOverrideGenerator( if (originalSymbol.fir.origin.fromSupertypes && originalSymbol.dispatchReceiverClassOrNull() == classLookupTag) { // Substitution case // NB: see comment above about substituted function' parent - val irDeclaration = cachedIrDeclaration(originalDeclaration)?.takeIf { it.parent == irClass } + val irDeclaration = cachedIrDeclaration(originalDeclaration) { + // Sometimes we can have clashing here when FIR substitution/intersection override + // have the same signature. + // Now we avoid this problem by signature caching, + // so both FIR overrides correspond to one IR fake override + signatureComposer.composeSignature(originalDeclaration) + }?.takeIf { it.parent == irClass } ?: createIrDeclaration( originalDeclaration, irClass, declarationStorage.findIrParent(baseSymbol.fir) as? IrClass, diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/FirCompileKotlinAgainstKotlinTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/FirCompileKotlinAgainstKotlinTestGenerated.java index 20d9e73b0c6..778ae6b9fc0 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/FirCompileKotlinAgainstKotlinTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/FirCompileKotlinAgainstKotlinTestGenerated.java @@ -410,6 +410,11 @@ public class FirCompileKotlinAgainstKotlinTestGenerated extends AbstractFirCompi runTest("compiler/testData/compileKotlinAgainstKotlin/fir/AnonymousObjectInProperty.kt"); } + @TestMetadata("ExistingSymbolInFakeOverride.kt") + public void testExistingSymbolInFakeOverride() throws Exception { + runTest("compiler/testData/compileKotlinAgainstKotlin/fir/ExistingSymbolInFakeOverride.kt"); + } + @TestMetadata("LibraryProperty.kt") public void testLibraryProperty() throws Exception { runTest("compiler/testData/compileKotlinAgainstKotlin/fir/LibraryProperty.kt"); diff --git a/compiler/testData/compileKotlinAgainstKotlin/fir/ExistingSymbolInFakeOverride.kt b/compiler/testData/compileKotlinAgainstKotlin/fir/ExistingSymbolInFakeOverride.kt new file mode 100644 index 00000000000..2450ef6b97b --- /dev/null +++ b/compiler/testData/compileKotlinAgainstKotlin/fir/ExistingSymbolInFakeOverride.kt @@ -0,0 +1,31 @@ +// TARGET_BACKEND: JVM +// FILE: A.kt + +interface KotlinMangler { + val String.hashMangle: Long + val D.fqnString: String + val D.fqnMangle: Long get() = fqnString.hashMangle + val manglerName: String + + interface IrMangler : KotlinMangler { + override val manglerName: String + get() = "Ir" + } +} + +abstract class AbstractKotlinMangler : KotlinMangler { + override val String.hashMangle get() = 42L +} + +abstract class IrBasedKotlinManglerImpl : AbstractKotlinMangler(), KotlinMangler.IrMangler { + override val String.fqnString: String + get() = this +} + +// FILE: B.kt + +abstract class AbstractJvmManglerIr : IrBasedKotlinManglerImpl() + +object JvmManglerIr : AbstractJvmManglerIr() + +fun box() = "OK" \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstKotlinTestGenerated.java index 22b1fae4578..89c3d1fb352 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstKotlinTestGenerated.java @@ -415,6 +415,11 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl runTest("compiler/testData/compileKotlinAgainstKotlin/fir/AnonymousObjectInProperty.kt"); } + @TestMetadata("ExistingSymbolInFakeOverride.kt") + public void testExistingSymbolInFakeOverride() throws Exception { + runTest("compiler/testData/compileKotlinAgainstKotlin/fir/ExistingSymbolInFakeOverride.kt"); + } + @TestMetadata("LibraryProperty.kt") public void testLibraryProperty() throws Exception { runTest("compiler/testData/compileKotlinAgainstKotlin/fir/LibraryProperty.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstKotlinTestGenerated.java index 4bc3662dc19..ff0ee5a8dd8 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstKotlinTestGenerated.java @@ -410,6 +410,11 @@ public class IrCompileKotlinAgainstKotlinTestGenerated extends AbstractIrCompile runTest("compiler/testData/compileKotlinAgainstKotlin/fir/AnonymousObjectInProperty.kt"); } + @TestMetadata("ExistingSymbolInFakeOverride.kt") + public void testExistingSymbolInFakeOverride() throws Exception { + runTest("compiler/testData/compileKotlinAgainstKotlin/fir/ExistingSymbolInFakeOverride.kt"); + } + @TestMetadata("LibraryProperty.kt") public void testLibraryProperty() throws Exception { runTest("compiler/testData/compileKotlinAgainstKotlin/fir/LibraryProperty.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmIrAgainstOldBoxTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmIrAgainstOldBoxTestGenerated.java index 7e6975e2b9a..45155e6a892 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmIrAgainstOldBoxTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmIrAgainstOldBoxTestGenerated.java @@ -410,6 +410,11 @@ public class JvmIrAgainstOldBoxTestGenerated extends AbstractJvmIrAgainstOldBoxT runTest("compiler/testData/compileKotlinAgainstKotlin/fir/AnonymousObjectInProperty.kt"); } + @TestMetadata("ExistingSymbolInFakeOverride.kt") + public void testExistingSymbolInFakeOverride() throws Exception { + runTest("compiler/testData/compileKotlinAgainstKotlin/fir/ExistingSymbolInFakeOverride.kt"); + } + @TestMetadata("LibraryProperty.kt") public void testLibraryProperty() throws Exception { runTest("compiler/testData/compileKotlinAgainstKotlin/fir/LibraryProperty.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmOldAgainstIrBoxTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmOldAgainstIrBoxTestGenerated.java index 0cce1de9307..88b78f1f0aa 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmOldAgainstIrBoxTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmOldAgainstIrBoxTestGenerated.java @@ -410,6 +410,11 @@ public class JvmOldAgainstIrBoxTestGenerated extends AbstractJvmOldAgainstIrBoxT runTest("compiler/testData/compileKotlinAgainstKotlin/fir/AnonymousObjectInProperty.kt"); } + @TestMetadata("ExistingSymbolInFakeOverride.kt") + public void testExistingSymbolInFakeOverride() throws Exception { + runTest("compiler/testData/compileKotlinAgainstKotlin/fir/ExistingSymbolInFakeOverride.kt"); + } + @TestMetadata("LibraryProperty.kt") public void testLibraryProperty() throws Exception { runTest("compiler/testData/compileKotlinAgainstKotlin/fir/LibraryProperty.kt");