diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt index b09979741ad..730ddf598da 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.* +import org.jetbrains.kotlin.fir.backend.generators.FakeOverrideGenerator import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall @@ -24,11 +25,8 @@ import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.SyntheticPropertySymbol import org.jetbrains.kotlin.fir.resolve.calls.originalConstructorIfTypeAlias import org.jetbrains.kotlin.fir.resolve.providers.FirProvider -import org.jetbrains.kotlin.fir.scopes.ProcessorAction +import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData -import org.jetbrains.kotlin.fir.scopes.processDirectlyOverriddenFunctions -import org.jetbrains.kotlin.fir.scopes.processDirectlyOverriddenProperties -import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope import org.jetbrains.kotlin.fir.symbols.AccessorSymbol import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* @@ -292,45 +290,89 @@ internal fun FirSimpleFunction.generateOverriddenFunctionSymbols( containingClass: FirClass<*>, session: FirSession, scopeSession: ScopeSession, - declarationStorage: Fir2IrDeclarationStorage + declarationStorage: Fir2IrDeclarationStorage, + fakeOverrideGenerator: FakeOverrideGenerator, ): List { + val superClasses = containingClass.getSuperTypesAsIrClasses(declarationStorage) ?: return emptyList() + val scope = containingClass.unsubstitutedScope(session, scopeSession, withForcedTypeCalculator = true) scope.processFunctionsByName(name) {} val overriddenSet = mutableSetOf() - scope.processDirectlyOverriddenFunctions(symbol) { + scope.processOverriddenFunctionsFromSuperClasses(symbol, containingClass) { if (it.fir.visibility == Visibilities.Private) { - return@processDirectlyOverriddenFunctions ProcessorAction.NEXT + return@processOverriddenFunctionsFromSuperClasses ProcessorAction.NEXT + } + + for (overridden in fakeOverrideGenerator.getOverriddenSymbolsInSupertypes(it, superClasses)) { + overriddenSet += overridden } - val overridden = declarationStorage.getIrFunctionSymbol(it.unwrapFakeOverrides()) - overriddenSet += overridden as IrSimpleFunctionSymbol ProcessorAction.NEXT } + return overriddenSet.toList() } +fun FirTypeScope.processOverriddenFunctionsFromSuperClasses( + functionSymbol: FirNamedFunctionSymbol, + containingClass: FirClass<*>, + processor: (FirNamedFunctionSymbol) -> ProcessorAction +): ProcessorAction = processDirectOverriddenFunctionsWithBaseScope(functionSymbol) { overridden, baseScope -> + val unwrapped = + overridden.fir.delegatedWrapperData?.takeIf { it.containingClass == containingClass.symbol.toLookupTag() }?.wrapped?.symbol + ?: overridden + + if (unwrapped.containingClass() == containingClass.symbol.toLookupTag()) { + baseScope.processOverriddenFunctionsFromSuperClasses(unwrapped, containingClass, processor) + } else { + processor(overridden) + } +} + +fun FirTypeScope.processOverriddenPropertiesFromSuperClasses( + propertySymbol: FirPropertySymbol, + containingClass: FirClass<*>, + processor: (FirPropertySymbol) -> ProcessorAction +): ProcessorAction = processDirectOverriddenPropertiesWithBaseScope(propertySymbol) { overridden, baseScope -> + if (overridden.containingClass() == containingClass.symbol.toLookupTag()) { + baseScope.processOverriddenPropertiesFromSuperClasses(overridden, containingClass, processor) + } else { + processor(overridden) + } +} + +private fun FirClass<*>.getSuperTypesAsIrClasses( + declarationStorage: Fir2IrDeclarationStorage +): Set? { + val irClass = + declarationStorage.classifierStorage.getIrClassSymbol(symbol).owner as? IrClass ?: return null + + return irClass.superTypes.mapNotNull { it.classifierOrNull?.owner as? IrClass }.toSet() +} + internal fun FirProperty.generateOverriddenAccessorSymbols( containingClass: FirClass<*>, isGetter: Boolean, session: FirSession, scopeSession: ScopeSession, - declarationStorage: Fir2IrDeclarationStorage + declarationStorage: Fir2IrDeclarationStorage, + fakeOverrideGenerator: FakeOverrideGenerator, ): List { val scope = containingClass.unsubstitutedScope(session, scopeSession, withForcedTypeCalculator = true) scope.processPropertiesByName(name) {} val overriddenSet = mutableSetOf() - scope.processDirectlyOverriddenProperties(symbol) { - if (it is FirAccessorSymbol || it.fir.visibility == Visibilities.Private) { - return@processDirectlyOverriddenProperties ProcessorAction.NEXT + val superClasses = containingClass.getSuperTypesAsIrClasses(declarationStorage) ?: return emptyList() + + scope.processOverriddenPropertiesFromSuperClasses(symbol, containingClass) { + if (it.fir.visibility == Visibilities.Private) { + return@processOverriddenPropertiesFromSuperClasses ProcessorAction.NEXT } - val unwrapped = - it.fir.delegatedWrapperData?.takeIf { it.containingClass == containingClass.symbol.toLookupTag() }?.wrapped?.symbol ?: it - - val overriddenProperty = declarationStorage.getIrPropertySymbol(unwrapped.unwrapFakeOverrides()) as IrPropertySymbol - val overriddenAccessor = if (isGetter) overriddenProperty.owner.getter?.symbol else overriddenProperty.owner.setter?.symbol - if (overriddenAccessor != null) { - overriddenSet += overriddenAccessor + for (overriddenProperty in fakeOverrideGenerator.getOverriddenSymbolsInSupertypes(it, superClasses)) { + val overriddenAccessor = if (isGetter) overriddenProperty.owner.getter?.symbol else overriddenProperty.owner.setter?.symbol + if (overriddenAccessor != null) { + overriddenSet += overriddenAccessor + } } ProcessorAction.NEXT } 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 04c2eb35488..77c3c4f438b 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 @@ -76,6 +76,23 @@ class Fir2IrDeclarationStorage( private val propertyCache = ConcurrentHashMap() + // interface A { /* $1 */ fun foo() } + // interface B : A { + // /* $2 */ fake_override fun foo() + // } + // interface C : B { + // /* $3 */ override fun foo() + // } + // + // We've got FIR declarations only for $1 and $3, but we've got a fake override for $2 in IR + // and just to simplify things we create a synthetic FIR for $2, while it can't be referenced from other FIR nodes. + // + // But when we binding overrides for $3, we want it had $2 ad it's overridden, + // so remember that in class B there's a fake override $2 for real $1. + // + // Thus we may obtain it by fakeOverridesInClass[ir(B)][fir(A::foo)] -> fir(B::foo) + private val fakeOverridesInClass = mutableMapOf, FirCallableDeclaration<*>>>() + // For pure fields (from Java) only private val fieldToPropertyCache = ConcurrentHashMap() @@ -633,7 +650,7 @@ class Fir2IrDeclarationStorage( } if (correspondingProperty is Fir2IrLazyProperty && !isFakeOverride && thisReceiverOwner != null) { this.overriddenSymbols = correspondingProperty.fir.generateOverriddenAccessorSymbols( - correspondingProperty.containingClass, !isSetter, session, scopeSession, declarationStorage + correspondingProperty.containingClass, !isSetter, session, scopeSession, declarationStorage, fakeOverrideGenerator ) } } @@ -835,6 +852,23 @@ class Fir2IrDeclarationStorage( delegatedReverseCache[irProperty] = property } + internal fun saveFakeOverrideInClass( + irClass: IrClass, + callableDeclaration: FirCallableDeclaration<*>, + fakeOverride: FirCallableDeclaration<*> + ) { + fakeOverridesInClass.getOrPut(irClass, ::mutableMapOf)[callableDeclaration] = fakeOverride + } + + fun getFakeOverrideInClass( + irClass: IrClass, + callableDeclaration: FirCallableDeclaration<*> + ): FirCallableDeclaration<*>? { + // Init lazy class if necessary + irClass.declarations + return fakeOverridesInClass[irClass]?.get(callableDeclaration) + } + fun getCachedIrField(field: FirField): IrField? = fieldCache[field] fun createIrFieldAndDelegatedMembers(field: FirField, owner: FirClass<*>, irClass: IrClass): IrField { @@ -1108,13 +1142,27 @@ class Fir2IrDeclarationStorage( val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED val declarationOrigin = computeDeclarationOrigin(firSymbol, parentOrigin) // 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" + when (val parent = irParent) { + is Fir2IrLazyClass -> { + assert(parentOrigin != IrDeclarationOrigin.DEFINED) { + "Should not have reference to public API uncached property from source code" + } + signature?.let { + return createIrLazyDeclaration(it, parent, declarationOrigin).symbol + } } - signature?.let { - return createIrLazyDeclaration(it, parent, declarationOrigin).symbol + is IrLazyClass -> { + val unwrapped = fir.unwrapFakeOverrides() + if (unwrapped !== fir) { + when (unwrapped) { + is FirSimpleFunction -> { + return getIrFunctionSymbol(unwrapped.symbol) + } + is FirProperty -> { + return getIrPropertySymbol(unwrapped.symbol) + } + } + } } } return createIrDeclaration(irParent, declarationOrigin).apply { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt index 0b709411cfb..4a76e3b3a6b 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt @@ -144,7 +144,7 @@ internal class ClassMemberGenerator( } if (irFunction is IrSimpleFunction && firFunction is FirSimpleFunction && containingClass != null) { irFunction.overriddenSymbols = firFunction.generateOverriddenFunctionSymbols( - containingClass, session, scopeSession, declarationStorage + containingClass, session, scopeSession, declarationStorage, fakeOverrideGenerator ) } } @@ -254,7 +254,7 @@ internal class ClassMemberGenerator( } if (containingClass != null) { this.overriddenSymbols = property.generateOverriddenAccessorSymbols( - containingClass, isGetter, session, scopeSession, declarationStorage + containingClass, isGetter, session, scopeSession, declarationStorage, fakeOverrideGenerator ) } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DelegatedMemberGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DelegatedMemberGenerator.kt index 5bba834af73..5bc798de0f9 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DelegatedMemberGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DelegatedMemberGenerator.kt @@ -132,7 +132,13 @@ internal class DelegatedMemberGenerator( containingClass = firSubClass.symbol.toLookupTag() ) delegateFunction.overriddenSymbols = - delegateOverride.generateOverriddenFunctionSymbols(firSubClass, session, scopeSession, declarationStorage) + delegateOverride.generateOverriddenFunctionSymbols( + firSubClass, + session, + scopeSession, + declarationStorage, + fakeOverrideGenerator + ) .filter { it.owner != delegateFunction } annotationGenerator.generate(delegateFunction, delegateOverride) @@ -201,13 +207,20 @@ internal class DelegatedMemberGenerator( delegateProperty.getter!!.body = createDelegateBody(irField, delegateProperty.getter!!, superProperty.getter!!) delegateProperty.getter!!.overriddenSymbols = - firDelegateProperty.generateOverriddenAccessorSymbols(firSubClass, isGetter = true, session, scopeSession, declarationStorage) + firDelegateProperty.generateOverriddenAccessorSymbols( + firSubClass, + isGetter = true, + session, + scopeSession, + declarationStorage, + fakeOverrideGenerator + ) annotationGenerator.generate(delegateProperty.getter!!, firDelegateProperty) if (delegateProperty.isVar) { delegateProperty.setter!!.body = createDelegateBody(irField, delegateProperty.setter!!, superProperty.setter!!) delegateProperty.setter!!.overriddenSymbols = firDelegateProperty.generateOverriddenAccessorSymbols( - firSubClass, isGetter = false, session, scopeSession, declarationStorage + firSubClass, isGetter = false, session, scopeSession, declarationStorage, fakeOverrideGenerator ) annotationGenerator.generate(delegateProperty.setter!!, firDelegateProperty) } 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 18602971925..a58abdb4f4c 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 @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.backend.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.resolve.defaultType +import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.impl.FirFakeOverrideGenerator import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData @@ -21,11 +22,10 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol -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.symbols.IrSymbol +import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.IdSignature +import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities class FakeOverrideGenerator( @@ -147,30 +147,34 @@ class FakeOverrideGenerator( val origin = IrDeclarationOrigin.FAKE_OVERRIDE val baseSymbol = originalSymbol.unwrapSubstitutionAndIntersectionOverrides() as S - val baseDeclaration = when { + + val (fakeOverrideFirDeclaration, baseFirSymbolsForFakeOverride) = when { originalSymbol.fir.origin.fromSupertypes && originalSymbol.dispatchReceiverClassOrNull() == classLookupTag -> { - // Substitution case - originalDeclaration + // Substitution or intersection case + // We have already a FIR declaration for such fake override + originalDeclaration to computeBaseSymbols(originalSymbol, computeDirectOverridden, scope, classLookupTag) } originalDeclaration.allowsToHaveFakeOverrideIn(klass) -> { // 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) + declarationStorage.saveFakeOverrideInClass(irClass, originalDeclaration, fakeOverrideSymbol.fir) classifierStorage.preCacheTypeParameters(originalDeclaration) - fakeOverrideSymbol.fir + fakeOverrideSymbol.fir to listOf(originalSymbol) } else -> { return } } - val irDeclaration = cachedIrDeclaration(baseDeclaration) { + val irDeclaration = cachedIrDeclaration(fakeOverrideFirDeclaration) { // 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(baseDeclaration) + signatureComposer.composeSignature(fakeOverrideFirDeclaration) }?.takeIf { it.parent == irClass } ?: createIrDeclaration( - baseDeclaration, + fakeOverrideFirDeclaration, irClass, /* thisReceiverOwner = */ declarationStorage.findIrParent(baseSymbol.fir) as? IrClass, origin, @@ -179,18 +183,20 @@ class FakeOverrideGenerator( if (containsErrorTypes(irDeclaration)) { return } - baseSymbols[irDeclaration] = computeBaseSymbols(originalSymbol, baseSymbol, computeDirectOverridden, scope, classLookupTag) + baseSymbols[irDeclaration] = baseFirSymbolsForFakeOverride result += irDeclaration } private inline fun > computeBaseSymbols( symbol: S, - basedSymbol: S, directOverridden: FirTypeScope.(S) -> List, scope: FirTypeScope, containingClass: ConeClassLikeLookupTag, ): List { - if (symbol.fir.origin != FirDeclarationOrigin.IntersectionOverride) return listOf(basedSymbol) + if (symbol.fir.origin == FirDeclarationOrigin.SubstitutionOverride) { + return listOf(symbol.originalForSubstitutionOverride!!) + } + return scope.directOverridden(symbol).map { // Unwrapping should happen only for fake overrides members from the same class, not from supertypes if (it.dispatchReceiverClassOrNull() != containingClass) return@map it @@ -204,8 +210,78 @@ class FakeOverrideGenerator( } } - internal fun getOverriddenSymbols(function: IrSimpleFunction): List? { - return baseFunctionSymbols[function]?.map { declarationStorage.getIrFunctionSymbol(it) as IrSimpleFunctionSymbol } + internal fun getOverriddenSymbolsForFakeOverride(function: IrSimpleFunction): List? { + val baseSymbols = baseFunctionSymbols[function] ?: return null + return getOverriddenSymbolsInSupertypes( + function, + baseSymbols + ) { declarationStorage.getIrFunctionSymbol(it) as IrSimpleFunctionSymbol } + } + + internal fun getOverriddenSymbolsInSupertypes( + overridden: FirNamedFunctionSymbol, + superClasses: Set, + ): List { + return getOverriddenSymbolsInSupertypes( + overridden, + superClasses + ) { declarationStorage.getIrFunctionSymbol(it) as IrSimpleFunctionSymbol } + } + + internal fun getOverriddenSymbolsInSupertypes( + overridden: FirPropertySymbol, + superClasses: Set, + ): List { + return getOverriddenSymbolsInSupertypes( + overridden, superClasses + ) { declarationStorage.getIrPropertySymbol(it) as IrPropertySymbol } + } + + private fun > getOverriddenSymbolsInSupertypes( + declaration: I, + baseSymbols: List, + irProducer: (F) -> S, + ): List { + val irClass = declaration.parentAsClass + val superClasses = irClass.superTypes.mapNotNull { it.classifierOrNull?.owner as? IrClass }.toSet() + + return baseSymbols.flatMap { overridden -> + getOverriddenSymbolsInSupertypes(overridden, superClasses, irProducer) + }.distinct() + } + + private fun , S : IrSymbol> getOverriddenSymbolsInSupertypes( + overridden: F, + superClasses: Set, + irProducer: (F) -> S + ): List { + val overriddenContainingClass = + overridden.containingClass()?.toSymbol(session)?.fir as? FirClass<*> ?: return emptyList() + + val overriddenContainingIrClass = + declarationStorage.classifierStorage.getIrClassSymbol(overriddenContainingClass.symbol).owner as? IrClass + ?: return emptyList() + + return if (overriddenContainingIrClass in superClasses) { + // `overridden` was a FIR declaration in some of the supertypes + listOf(irProducer(overridden)) + } else { + // There were no FIR declaration in supertypes, but we know that we have fake overrides in some of them + superClasses.mapNotNull { + declarationStorage.getFakeOverrideInClass(it, overridden.fir)?.let { fakeOverrideInClass -> + @Suppress("UNCHECKED_CAST") + irProducer(fakeOverrideInClass.symbol as F) + } + }.run { + // TODO: Get rid of this hack + // It's only needed for built-in super classes, because they are built via descriptors and + // don't register fake overrides at org.jetbrains.kotlin.fir.backend.Fir2IrDeclarationStorage.fakeOverridesInClass + if (isEmpty()) + listOf(irProducer(overridden)) + else + this + } + } } fun bindOverriddenSymbols(declarations: List) { @@ -213,7 +289,7 @@ class FakeOverrideGenerator( if (declaration.origin != IrDeclarationOrigin.FAKE_OVERRIDE) continue when (declaration) { is IrSimpleFunction -> { - val baseSymbols = getOverriddenSymbols(declaration)!! + val baseSymbols = getOverriddenSymbolsForFakeOverride(declaration)!! declaration.withFunction { overriddenSymbols = baseSymbols } @@ -249,9 +325,10 @@ class FakeOverrideGenerator( isVar: Boolean, firOverriddenSymbols: List ): IrProperty { - val overriddenIrProperties = firOverriddenSymbols.mapNotNull { - (declarationStorage.getIrPropertySymbol(it) as? IrPropertySymbol)?.owner - } + val overriddenIrProperties = getOverriddenSymbolsInSupertypes(this, firOverriddenSymbols) { + declarationStorage.getIrPropertySymbol(it) as IrPropertySymbol + }.map { it.owner } + getter?.apply { overriddenSymbols = overriddenIrProperties.mapNotNull { it.getter?.symbol } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt index 30c2d974326..cba4f9b9642 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt @@ -71,7 +71,7 @@ class Fir2IrLazySimpleFunction( val parent = parent if (isFakeOverride && parent is Fir2IrLazyClass) { parent.declarations - fakeOverrideGenerator.getOverriddenSymbols(this)?.let { return@lazyVar it } + fakeOverrideGenerator.getOverriddenSymbolsForFakeOverride(this)?.let { return@lazyVar it } } fir.generateOverriddenFunctionSymbols(firParent, session, scopeSession, declarationStorage, fakeOverrideGenerator) } diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 5abc0ae47ae..9cf4c768fe8 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -37768,6 +37768,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/specialBuiltins/commonBridgesTarget.kt"); } + @Test + @TestMetadata("complexMapImpl.kt") + public void testComplexMapImpl() throws Exception { + runTest("compiler/testData/codegen/box/specialBuiltins/complexMapImpl.kt"); + } + @Test @TestMetadata("emptyList.kt") public void testEmptyList() throws Exception { diff --git a/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/abstractMap.kt b/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/abstractMap.kt index 18bb26f2000..0447f569b20 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/abstractMap.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/abstractMap.kt @@ -1,6 +1,5 @@ // DONT_TARGET_EXACT_BACKEND: WASM // WASM_MUTE_REASON: STDLIB_COLLECTIONS -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM import java.util.AbstractMap diff --git a/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/abstractSet.kt b/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/abstractSet.kt index 74898483503..35220c7c15b 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/abstractSet.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/abstractSet.kt @@ -1,6 +1,5 @@ // DONT_TARGET_EXACT_BACKEND: WASM // WASM_MUTE_REASON: STDLIB_COLLECTIONS -// IGNORE_BACKEND_FIR: JVM_IR // KJS_WITH_FULL_RUNTIME // IGNORE_BACKEND: NATIVE class A : HashSet() diff --git a/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/hashMap.kt b/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/hashMap.kt index 24eabb0410c..87117ba74a9 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/hashMap.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/hashMap.kt @@ -1,6 +1,5 @@ // DONT_TARGET_EXACT_BACKEND: WASM // WASM_MUTE_REASON: STDLIB_COLLECTIONS -// IGNORE_BACKEND_FIR: JVM_IR // KJS_WITH_FULL_RUNTIME // IGNORE_BACKEND: NATIVE class A : HashMap() diff --git a/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/hashSet.kt b/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/hashSet.kt index 74898483503..35220c7c15b 100644 --- a/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/hashSet.kt +++ b/compiler/testData/codegen/box/builtinStubMethods/extendJavaCollections/hashSet.kt @@ -1,6 +1,5 @@ // DONT_TARGET_EXACT_BACKEND: WASM // WASM_MUTE_REASON: STDLIB_COLLECTIONS -// IGNORE_BACKEND_FIR: JVM_IR // KJS_WITH_FULL_RUNTIME // IGNORE_BACKEND: NATIVE class A : HashSet() diff --git a/compiler/testData/codegen/box/casts/mutableCollections/mutabilityMarkerInterfaces.kt b/compiler/testData/codegen/box/casts/mutableCollections/mutabilityMarkerInterfaces.kt index b8bef669c95..743a5f31cc1 100644 --- a/compiler/testData/codegen/box/casts/mutableCollections/mutabilityMarkerInterfaces.kt +++ b/compiler/testData/codegen/box/casts/mutableCollections/mutabilityMarkerInterfaces.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/collections/addCollectionStubWithCovariantOverride.kt b/compiler/testData/codegen/box/collections/addCollectionStubWithCovariantOverride.kt index 06b6217706d..c30c17b2c97 100644 --- a/compiler/testData/codegen/box/collections/addCollectionStubWithCovariantOverride.kt +++ b/compiler/testData/codegen/box/collections/addCollectionStubWithCovariantOverride.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR - abstract class AbstractAdd { abstract fun add(s: String): Any } @@ -23,4 +21,4 @@ fun test2(a: AbstractStringCollection) = a.add("K") as String fun box() = - test1(StringCollection()) + test2(StringCollection()) \ No newline at end of file + test1(StringCollection()) + test2(StringCollection()) diff --git a/compiler/testData/codegen/box/collections/javaCollectionWithRemovePrimitiveInt.kt b/compiler/testData/codegen/box/collections/javaCollectionWithRemovePrimitiveInt.kt index 15c4643bd45..7768bd068eb 100644 --- a/compiler/testData/codegen/box/collections/javaCollectionWithRemovePrimitiveInt.kt +++ b/compiler/testData/codegen/box/collections/javaCollectionWithRemovePrimitiveInt.kt @@ -1,5 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_BACKEND_FIR: JVM_IR // WITH_RUNTIME // FILE: javaCollectionWithRemovePrimitiveInt.kt diff --git a/compiler/testData/codegen/box/specialBuiltins/bridges.kt b/compiler/testData/codegen/box/specialBuiltins/bridges.kt index ebad83489a5..a09f84857e8 100644 --- a/compiler/testData/codegen/box/specialBuiltins/bridges.kt +++ b/compiler/testData/codegen/box/specialBuiltins/bridges.kt @@ -1,6 +1,5 @@ // DONT_TARGET_EXACT_BACKEND: WASM // WASM_MUTE_REASON: STDLIB_COLLECTIONS -// IGNORE_BACKEND_FIR: JVM_IR // KJS_WITH_FULL_RUNTIME // IGNORE_BACKEND: NATIVE diff --git a/compiler/testData/codegen/box/specialBuiltins/complexMapImpl.kt b/compiler/testData/codegen/box/specialBuiltins/complexMapImpl.kt new file mode 100644 index 00000000000..0dc7fce94a4 --- /dev/null +++ b/compiler/testData/codegen/box/specialBuiltins/complexMapImpl.kt @@ -0,0 +1,131 @@ +// TARGET_BACKEND: JVM +// WITH_RUNTIME + +// binary representation of fractional part of phi = (sqrt(5) - 1) / 2 +private const val MAGIC: Int = 0x9E3779B9L.toInt() // ((sqrt(5.0) - 1) / 2 * pow(2.0, 32.0)).toLong().toString(16) +private const val MAX_SHIFT = 27 +private const val THRESHOLD = ((1L shl 31) - 1).toInt() // 50% fill factor for speed +private val EMPTY_ARRAY = arrayOf() + + +// For more details see for Knuth's multiplicative hash with golden ratio +// Shortly, we're trying to keep distribution of it uniform independently of input +// It's necessary because we use very simple linear probing +@Suppress("NOTHING_TO_INLINE") +private inline fun Any.computeHash(shift: Int) = ((hashCode() * MAGIC) ushr shift) shl 1 + + +internal class OpenAddressLinearProbingHashTable : AbstractMutableMap() { + // fields be initialized later in `clear()` + + // capacity = 1 << (32 - shift) + private var shift = 0 + // keys are stored in even elements, values are in odd ones + private var array = EMPTY_ARRAY + private var size_ = 0 + + init { + clear() + } + + override val size + get() = size_ + + override fun get(key: K): V? { + var i = key.computeHash(shift) + var k = array[i] + + while (true) { + if (k === null) return null + @Suppress("UNCHECKED_CAST") + if (k == key) return array[i + 1] as V + if (i == 0) { + i = array.size + } + i -= 2 + k = array[i] + } + } + + /** + * Never returns previous values + */ + override fun put(key: K, value: V): V? { + if (put(array, shift, key, value)) { + if (++size_ >= (THRESHOLD ushr shift)) { + rehash() + } + } + + return null + } + + private fun rehash() { + val newShift = maxOf(shift - 3, 0) + val newArraySize = 1 shl (33 - newShift) + val newArray = arrayOfNulls(newArraySize) + + var i = 0 + val arraySize = array.size + while (i < arraySize) { + val key = array[i] + if (key != null) { + put(newArray, newShift, key, array[i + 1]) + } + i += 2 + } + + shift = newShift + array = newArray + } + + override fun clear() { + shift = MAX_SHIFT + array = arrayOfNulls(1 shl (33 - shift)) + + size_ = 0 + } + + override val entries: MutableSet> + get() { + + throw IllegalStateException("OpenAddressLinearProbingHashTable::entries is not supported and hardly will be") + } + + private class Entry(override val key: K, override val value: V) : MutableMap.MutableEntry { + override fun setValue(newValue: V): V = throw UnsupportedOperationException("This Entry is not mutable.") + } + + companion object { + // Change to "true" to be able to see the contents of the map in debugger views + private const val DEBUG = false + } +} + +private fun put(array: Array, aShift: Int, key: Any, value: Any?): Boolean { + var i = key.computeHash(aShift) + + while (true) { + val k = array[i] + if (k == null) { + array[i] = key + array[i + 1] = value + return true + } + if (k == key) break + if (i == 0) { + i = array.size + } + i -= 2 + } + + array[i + 1] = value + + return false +} + +fun box(): String { + val map = OpenAddressLinearProbingHashTable() + map.put("O", "K") + return "O" + map["O"] +} diff --git a/compiler/testData/codegen/box/specialBuiltins/specialBridgeModality.kt b/compiler/testData/codegen/box/specialBuiltins/specialBridgeModality.kt index d19b1e9fced..fa05e9afb2a 100644 --- a/compiler/testData/codegen/box/specialBuiltins/specialBridgeModality.kt +++ b/compiler/testData/codegen/box/specialBuiltins/specialBridgeModality.kt @@ -1,5 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_BACKEND_FIR: JVM_IR import java.util.AbstractMap diff --git a/compiler/testData/codegen/box/traits/defaultImplCall.kt b/compiler/testData/codegen/box/traits/defaultImplCall.kt index 6b0eed7c16a..d3ebe55a400 100644 --- a/compiler/testData/codegen/box/traits/defaultImplCall.kt +++ b/compiler/testData/codegen/box/traits/defaultImplCall.kt @@ -1,5 +1,4 @@ // !JVM_DEFAULT_MODE: disable -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // First item on Android is `java.lang.Thread.getStackTrace` diff --git a/compiler/testData/codegen/bytecodeText/builtinFunctions/genericParameterBridge/abstractList.kt b/compiler/testData/codegen/bytecodeText/builtinFunctions/genericParameterBridge/abstractList.kt index 58c312ddee0..474ecbc0b74 100644 --- a/compiler/testData/codegen/bytecodeText/builtinFunctions/genericParameterBridge/abstractList.kt +++ b/compiler/testData/codegen/bytecodeText/builtinFunctions/genericParameterBridge/abstractList.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR abstract class A3 : java.util.AbstractList() abstract class A4 : java.util.AbstractList() { override fun contains(o: W): Boolean { diff --git a/compiler/testData/codegen/bytecodeText/interfaces/traitImplGeneratedOnce.kt b/compiler/testData/codegen/bytecodeText/interfaces/traitImplGeneratedOnce.kt index 0c0c81ce6ac..e308c0d92dc 100644 --- a/compiler/testData/codegen/bytecodeText/interfaces/traitImplGeneratedOnce.kt +++ b/compiler/testData/codegen/bytecodeText/interfaces/traitImplGeneratedOnce.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR interface A { fun foo() = 42 } diff --git a/compiler/testData/codegen/bytecodeText/mapGetOrDefault.kt b/compiler/testData/codegen/bytecodeText/mapGetOrDefault.kt index c8eff9871ee..c954bdaf1b8 100644 --- a/compiler/testData/codegen/bytecodeText/mapGetOrDefault.kt +++ b/compiler/testData/codegen/bytecodeText/mapGetOrDefault.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // JVM_TARGET: 1.8 // WITH_RUNTIME // FULL_JDK @@ -38,4 +37,4 @@ class MyMap: TestMap() // JVM_IR_TEMPLATES: // 1 public bridge getOrDefault\(Ljava/lang/String;Ljava/lang/String;\)Ljava/lang/String; -// 1 public final bridge getOrDefault\(Ljava/lang/Object;Ljava/lang/String;\)Ljava/lang/String; \ No newline at end of file +// 1 public final bridge getOrDefault\(Ljava/lang/Object;Ljava/lang/String;\)Ljava/lang/String; diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index f6cf267f639..9747a653863 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -37768,6 +37768,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/specialBuiltins/commonBridgesTarget.kt"); } + @Test + @TestMetadata("complexMapImpl.kt") + public void testComplexMapImpl() throws Exception { + runTest("compiler/testData/codegen/box/specialBuiltins/complexMapImpl.kt"); + } + @Test @TestMetadata("emptyList.kt") public void testEmptyList() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 45d24688c10..23fb86aa543 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -37768,6 +37768,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/specialBuiltins/commonBridgesTarget.kt"); } + @Test + @TestMetadata("complexMapImpl.kt") + public void testComplexMapImpl() throws Exception { + runTest("compiler/testData/codegen/box/specialBuiltins/complexMapImpl.kt"); + } + @Test @TestMetadata("emptyList.kt") public void testEmptyList() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 1b704cb4793..9be202977b2 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -30208,6 +30208,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/specialBuiltins/commonBridgesTarget.kt"); } + @TestMetadata("complexMapImpl.kt") + public void testComplexMapImpl() throws Exception { + runTest("compiler/testData/codegen/box/specialBuiltins/complexMapImpl.kt"); + } + @TestMetadata("emptyList.kt") public void testEmptyList() throws Exception { runTest("compiler/testData/codegen/box/specialBuiltins/emptyList.kt");