diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/convertToIr.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/convertToIr.kt index 9c43eab03c1..be5871b59ba 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/convertToIr.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/convertToIr.kt @@ -21,9 +21,11 @@ import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmDescriptorMangler import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl +import org.jetbrains.kotlin.ir.overrides.buildForAll import org.jetbrains.kotlin.ir.types.IrTypeSystemContext import org.jetbrains.kotlin.ir.util.IdSignatureComposer import org.jetbrains.kotlin.ir.util.KotlinMangler +import org.jetbrains.kotlin.ir.visitors.acceptVoid data class FirResult(val outputs: List) @@ -61,85 +63,58 @@ fun FirResult.convertToIrAndActualize( actualizerTypeContextProvider: (IrBuiltIns) -> IrTypeSystemContext, fir2IrResultPostCompute: (ModuleCompilerAnalyzedOutput, Fir2IrResult) -> Unit = { _, _ -> }, ): Fir2IrActualizedResult { - val fir2IrResult: Fir2IrResult - val actualizationResult: IrActualizedResult? - val commonMemberStorage = Fir2IrCommonMemberStorage(signatureComposer, firMangler) - when (outputs.size) { - 0 -> error("No modules found") - 1 -> { - val output = outputs.single() - fir2IrResult = convertToIr( - output, - fir2IrExtensions, - fir2IrConfiguration, - commonMemberStorage = commonMemberStorage, - irBuiltIns = null, - irMangler, - visibilityConverter, - kotlinBuiltIns, - actualizerTypeContextProvider, - ).also { result -> - fir2IrResultPostCompute(output, result) - } - actualizationResult = null - } - else -> { - val platformOutput = outputs.last() - val commonOutputs = outputs.dropLast(1) - var irBuiltIns: IrBuiltInsOverFir? = null - val commonIrOutputs = commonOutputs.map { - convertToIr( - it, - // We need to build all modules before rebuilding fake overrides - // to avoid fixing declaration storages - fir2IrExtensions, - fir2IrConfiguration.copy(useIrFakeOverrideBuilder = false), - commonMemberStorage = commonMemberStorage, - irBuiltIns = irBuiltIns, - irMangler, - visibilityConverter, - kotlinBuiltIns, - actualizerTypeContextProvider, - ).also { result -> - fir2IrResultPostCompute(it, result) - if (irBuiltIns == null) { - irBuiltIns = result.components.irBuiltIns - } - } - } - fir2IrResult = convertToIr( - platformOutput, - fir2IrExtensions, - fir2IrConfiguration, - commonMemberStorage = commonMemberStorage, - irBuiltIns = irBuiltIns!!, - irMangler, - visibilityConverter, - kotlinBuiltIns, - actualizerTypeContextProvider, - ).also { - fir2IrResultPostCompute(platformOutput, it) - } + require(outputs.isNotEmpty()) { "No modules found" } - actualizationResult = IrActualizer.actualize( - fir2IrResult.irModuleFragment, - commonIrOutputs.map { it.irModuleFragment }, - KtDiagnosticReporterWithImplicitIrBasedContext( - fir2IrConfiguration.diagnosticReporter, - fir2IrConfiguration.languageVersionSettings - ), - actualizerTypeContextProvider(fir2IrResult.irModuleFragment.irBuiltins), - commonMemberStorage.symbolTable, - fir2IrResult.components.fakeOverrideBuilder, - fir2IrConfiguration.useIrFakeOverrideBuilder, - fir2IrConfiguration.expectActualTracker, - ) + var irBuiltIns: IrBuiltInsOverFir? = null + val irOutputs = outputs.map { + convertToIr( + it, + // We need to build all modules before rebuilding fake overrides + // to avoid fixing declaration storages + fir2IrExtensions, + fir2IrConfiguration, + commonMemberStorage = commonMemberStorage, + irBuiltIns = irBuiltIns, + irMangler, + visibilityConverter, + kotlinBuiltIns, + actualizerTypeContextProvider, + ).also { result -> + fir2IrResultPostCompute(it, result) + if (irBuiltIns == null) { + irBuiltIns = result.components.irBuiltIns + } } } - val (irModuleFragment, components, pluginContext) = fir2IrResult + val (irModuleFragment, components, pluginContext) = irOutputs.last() + val allIrModules = irOutputs.map { it.irModuleFragment } + + val irActualizer = if (allIrModules.size == 1) null else IrActualizer( + KtDiagnosticReporterWithImplicitIrBasedContext( + fir2IrConfiguration.diagnosticReporter, + fir2IrConfiguration.languageVersionSettings + ), + actualizerTypeContextProvider(irModuleFragment.irBuiltins), + fir2IrConfiguration.expectActualTracker, + fir2IrConfiguration.useIrFakeOverrideBuilder, + irModuleFragment, + allIrModules.dropLast(1), + ) + + if (fir2IrConfiguration.useIrFakeOverrideBuilder) { + // actualizeCallablesAndMergeModules call below in fact can also actualize classifiers. + // So to avoid even more changes, when this mode is disabled, we don't run classifiers + // actualization separately. This should go away, after useIrFakeOverrideBuilder becomes + // always enabled + irActualizer?.actualizeClassifiers() + components.fakeOverrideBuilder.buildForAll(allIrModules) + } + val expectActualMap = irActualizer?.actualizeCallablesAndMergeModules() ?: emptyMap() + Fir2IrConverter.evaluateConstants(irModuleFragment, components) + val actualizationResult = irActualizer?.runChecksAndFinalize(expectActualMap) pluginContext.applyIrGenerationExtensions(irModuleFragment, irGeneratorExtensions) return Fir2IrActualizedResult(irModuleFragment, components, pluginContext, actualizationResult) } 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 a0a1027cefb..ab5bf82e10f 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 @@ -11,7 +11,6 @@ import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtPsiSourceFileLinesMapping import org.jetbrains.kotlin.KtSourceFileLinesMappingFromLineStartOffsets import org.jetbrains.kotlin.backend.common.CommonBackendErrors -import org.jetbrains.kotlin.ir.overrides.FakeOverrideRebuilder import org.jetbrains.kotlin.backend.common.sourceElement import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.config.LanguageFeature @@ -129,8 +128,6 @@ class Fir2IrConverter( @OptIn(LeakedDeclarationCaches::class) declarationStorage.fillUnboundSymbols() } - - evaluateConstants(irModuleFragment, components) } fun bindFakeOverridesOrPostpone(declarations: List) { @@ -618,7 +615,8 @@ class Fir2IrConverter( } companion object { - private fun evaluateConstants(irModuleFragment: IrModuleFragment, components: Fir2IrComponents) { + // TODO: move to compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/convertToIr.kt (KT-64201) + fun evaluateConstants(irModuleFragment: IrModuleFragment, components: Fir2IrComponents) { val fir2IrConfiguration = components.configuration val firModuleDescriptor = irModuleFragment.descriptor as? FirModuleDescriptor val targetPlatform = firModuleDescriptor?.platform @@ -745,11 +743,6 @@ class Fir2IrConverter( components.fir2IrVisitor ) - if (fir2IrConfiguration.useIrFakeOverrideBuilder) { - val rebuilder = FakeOverrideRebuilder(commonMemberStorage.symbolTable, components.fakeOverrideBuilder) - rebuilder.rebuildFakeOverrides(irModuleFragment) - } - return Fir2IrResult(irModuleFragment, components, moduleDescriptor) } } diff --git a/compiler/ir/ir.actualization/src/main/kotlin/org/jetbrains/kotlin/backend/common/actualizer/ExpectActualCollector.kt b/compiler/ir/ir.actualization/src/main/kotlin/org/jetbrains/kotlin/backend/common/actualizer/ExpectActualCollector.kt index 94cc581507a..86b49710bb9 100644 --- a/compiler/ir/ir.actualization/src/main/kotlin/org/jetbrains/kotlin/backend/common/actualizer/ExpectActualCollector.kt +++ b/compiler/ir/ir.actualization/src/main/kotlin/org/jetbrains/kotlin/backend/common/actualizer/ExpectActualCollector.kt @@ -49,17 +49,15 @@ internal class ExpectActualCollector( private val diagnosticsReporter: IrDiagnosticReporter, private val expectActualTracker: ExpectActualTracker?, ) { - data class Result(val expectToActualMap: MutableMap, val classActualizationInfo: ClassActualizationInfo) - fun collect(): Result { + fun collect(actualDeclarations: ClassActualizationInfo): MutableMap { val result = mutableMapOf() // Collect and link classes at first to make it possible to expand type aliases on the members linking - val actualDeclarations = collectActualDeclarations() matchAllExpectDeclarations(result, actualDeclarations) - return Result(result, actualDeclarations) + return result } - private fun collectActualDeclarations(): ClassActualizationInfo { + fun collectClassActualizationInfo(): ClassActualizationInfo { val expectTopLevelClasses = ExpectTopLevelClassesCollector.collect(dependentFragments) val fragmentsWithActuals = dependentFragments.drop(1) + mainFragment return ActualDeclarationsCollector.collectActualsFromFragments(fragmentsWithActuals, expectTopLevelClasses) diff --git a/compiler/ir/ir.actualization/src/main/kotlin/org/jetbrains/kotlin/backend/common/actualizer/IrActualizer.kt b/compiler/ir/ir.actualization/src/main/kotlin/org/jetbrains/kotlin/backend/common/actualizer/IrActualizer.kt index 490bf5d9ba0..cfa500ff9b4 100644 --- a/compiler/ir/ir.actualization/src/main/kotlin/org/jetbrains/kotlin/backend/common/actualizer/IrActualizer.kt +++ b/compiler/ir/ir.actualization/src/main/kotlin/org/jetbrains/kotlin/backend/common/actualizer/IrActualizer.kt @@ -9,13 +9,18 @@ import org.jetbrains.kotlin.ir.IrDiagnosticReporter import org.jetbrains.kotlin.backend.common.actualizer.checker.IrExpectActualCheckers import org.jetbrains.kotlin.incremental.components.ExpectActualTracker import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.overrides.FakeOverrideRebuilder -import org.jetbrains.kotlin.ir.overrides.IrFakeOverrideBuilder +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.types.IrTypeSystemContext +import org.jetbrains.kotlin.ir.types.classOrFail import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled -data class IrActualizedResult(val actualizedExpectDeclarations: List) +data class IrActualizedResult( + val actualizedExpectDeclarations: List, + val expectActualMap: Map +) /** * IrActualizer is responsible for performing actualization. @@ -24,34 +29,53 @@ data class IrActualizedResult(val actualizedExpectDeclarations: List, - ktDiagnosticReporter: IrDiagnosticReporter, - typeSystemContext: IrTypeSystemContext, - symbolTable: SymbolTable, - fakeOverrideBuilder: IrFakeOverrideBuilder, - useIrFakeOverrideBuilder: Boolean, - expectActualTracker: ExpectActualTracker? - ): IrActualizedResult { +class IrActualizer( + val ktDiagnosticReporter: IrDiagnosticReporter, + val typeSystemContext: IrTypeSystemContext, + expectActualTracker: ExpectActualTracker?, + val useIrFakeOverrideBuilder: Boolean, + val mainFragment: IrModuleFragment, + val dependentFragments: List +) { + private val collector = ExpectActualCollector( + mainFragment, + dependentFragments, + typeSystemContext, + ktDiagnosticReporter, + expectActualTracker, + ) - // The ir modules processing is performed phase-to-phase: - // 1. Collect expect-actual links for classes and their members from dependent fragments - val (expectActualMap, actualDeclarations) = ExpectActualCollector( - mainFragment, - dependentFragments, - typeSystemContext, - ktDiagnosticReporter, - expectActualTracker - ).collect() + private val classActualizationInfo = collector.collectClassActualizationInfo() - IrExpectActualCheckers(expectActualMap, actualDeclarations, typeSystemContext, ktDiagnosticReporter).check() + fun actualizeClassifiers() { + val classSymbolRemapper = object : SymbolRemapper.Empty() { + override fun getReferencedClass(symbol: IrClassSymbol): IrClassSymbol { + if (!symbol.owner.isExpect) return symbol + if (symbol.owner.containsOptionalExpectation()) return symbol + val classId = symbol.owner.classIdOrFail + classActualizationInfo.actualTypeAliases[classId]?.let { return it.owner.expandedType.classOrFail } + classActualizationInfo.actualClasses[classId]?.let { return it } + shouldNotBeCalled("There is no actual class for ${classId}, but this should be already rejected by frontend upto this point") + } - // 2. Remove top-only expect declarations since they are not needed anymore and should not be presented in the final IrFragment - // Expect fake-overrides from non-expect classes remain untouched since they will be actualized in the next phase. - // Also, it doesn't remove unactualized expect declarations marked with @OptionalExpectation - val removedExpectDeclarations = removeExpectDeclarations(dependentFragments, expectActualMap) + override fun getReferencedClassOrNull(symbol: IrClassSymbol?): IrClassSymbol? { + if (symbol == null) return null + return getReferencedClass(symbol) + } + + override fun getReferencedClassifier(symbol: IrClassifierSymbol): IrClassifierSymbol { + if (symbol !is IrClassSymbol) return symbol + return getReferencedClass(symbol) + } + } + val classTypeRemapper = DeepCopyTypeRemapper(classSymbolRemapper) + val classActualizerVisitor = ActualizerVisitor(classSymbolRemapper, classTypeRemapper) + dependentFragments.forEach { it.transform(classActualizerVisitor, null) } + } + + fun actualizeCallablesAndMergeModules(): Map { + // 1. Collect expect-actual links for members of classes found on step 1. + val expectActualMap = collector.collect(classActualizationInfo) if (!useIrFakeOverrideBuilder) { // 3. Actualize expect fake overrides in non-expect classes inside common or multi-platform module. @@ -62,7 +86,7 @@ object IrActualizer { // taken from these non-expect classes actualized super classes. ActualFakeOverridesAdder( expectActualMap, - actualDeclarations.actualClasses, + classActualizationInfo.actualClasses, typeSystemContext ).apply { dependentFragments.forEach { visitModuleFragment(it) } } } @@ -76,15 +100,18 @@ object IrActualizer { val actualizerVisitor = ActualizerVisitor(symbolRemapper, typeRemapper) dependentFragments.forEach { it.transform(actualizerVisitor, null) } - // 7. Merge dependent fragments into the main one + // 8. Move all declarations to mainFragment mergeIrFragments(mainFragment, dependentFragments) + return expectActualMap + } - if (useIrFakeOverrideBuilder) { - // 8. Rebuild fake overrides from stretch, as they could become invalid during actualization - FakeOverrideRebuilder(symbolTable, fakeOverrideBuilder).rebuildFakeOverrides(mainFragment) - } + fun runChecksAndFinalize(expectActualMap: Map) : IrActualizedResult { + // Remove top-only expect declarations since they are not needed anymore and should not be presented in the final IrFragment + // Also, it doesn't remove unactualized expect declarations marked with @OptionalExpectation + val removedExpectDeclarations = removeExpectDeclarations(dependentFragments, expectActualMap) - return IrActualizedResult(removedExpectDeclarations) + IrExpectActualCheckers(expectActualMap, classActualizationInfo, typeSystemContext, ktDiagnosticReporter).check() + return IrActualizedResult(removedExpectDeclarations, expectActualMap) } private fun removeExpectDeclarations(dependentFragments: List, expectActualMap: Map): List { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/FakeOverrideRebuilder.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/FakeOverrideRebuilder.kt deleted file mode 100644 index 662a7a7422a..00000000000 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/FakeOverrideRebuilder.kt +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.ir.overrides - -import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyDeclarationBase -import org.jetbrains.kotlin.ir.expressions.IrCall -import org.jetbrains.kotlin.ir.expressions.IrFunctionReference -import org.jetbrains.kotlin.ir.expressions.IrLocalDelegatedPropertyReference -import org.jetbrains.kotlin.ir.expressions.IrPropertyReference -import org.jetbrains.kotlin.ir.symbols.IrClassSymbol -import org.jetbrains.kotlin.ir.symbols.IrSymbol -import org.jetbrains.kotlin.ir.types.getClass -import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid -import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid -import org.jetbrains.kotlin.ir.visitors.acceptVoid -import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled -import org.jetbrains.kotlin.utils.newHashSetWithExpectedSize - -/** - * After actualization, fake overrides can be incorrect. - * - * Fake overrides can change even in classes, which don't have expect/actuals in their superclasses. - * And this change can be more non-trivial than just substituting expect class with actual. - * - * For example, if an expect class is actualized to a common class, or several expect classes are actualized to the same class, - * several fake overrides can be merged with each other, or with real functions. - * - * To fix that, we are just rebuilding fake overrides from scratch, after actualization is done. - * - * This is done in 3 steps: - * 1. Remove all fake overrides from all declarations, and remove their symbols from the symbol table. - * 2. Build new fake overrides and map the old one to some function now existing in the class (which can also be a real function). - * 3. Remap call-sites of all functions using the map collected on step 2. - * - * Steps 1 and 3 are kinda trivial, except we should remove all fake overrides from symbol table. - * - * For matching in step 2, classes are processed in such order, that the superclass is processed before each class. - * This allows us to match using `overriddenSymbols`. In particular, f/o is mapped to only function - * overriding any of functions (possibly already mapped), which was overridden by initial fake override. - * - * Here we assume that functions can only be merged, not split, i.e. if the same fake override was overriding several - * super-functions, it's impossible to have different function overriding them after actualization. - */ -class FakeOverrideRebuilder( - val symbolTable: SymbolTable, - val fakeOverrideBuilder: IrFakeOverrideBuilder, -) { - private val removedFakeOverrides = mutableMapOf>() - private val processedClasses = hashSetOf() - - // Map from the old fake override symbol to the new (rebuilt) symbol. - private val fakeOverrideMap = hashMapOf() - - - fun rebuildFakeOverrides(irModule: IrModuleFragment) { - irModule.acceptVoid(RemoveFakeOverridesVisitor(removedFakeOverrides, symbolTable)) - for (clazz in removedFakeOverrides.keys) { - rebuildClassFakeOverrides(clazz.owner) - } - irModule.acceptVoid(RemapFakeOverridesVisitor(fakeOverrideMap)) - } - - private fun collectOverriddenDeclarations( - member: IrOverridableDeclaration<*>, - result: MutableSet>, - visited: MutableSet>, - stopAtReal: Boolean, - ) { - if (!visited.add(member)) return - if (member.isReal) { - result.add(member) - if (stopAtReal) return - } else { - require(member.overriddenSymbols.isNotEmpty()) { "No overridden symbols found for (fake override) ${member.render()}" } - } - for (overridden in member.overriddenSymbols) { - collectOverriddenDeclarations(overridden.owner as IrOverridableDeclaration<*>, result, visited, stopAtReal) - } - } - - private fun IrOverridableDeclaration<*>.getOverriddenDeclarations(stopAtReal: Boolean): Set> = - mutableSetOf>().also { result -> - collectOverriddenDeclarations(this, result, hashSetOf(), stopAtReal) - } - - private fun MutableMap.processDeclaration(declaration: IrOverridableDeclaration<*>, irClass: IrClass) { - for (overridden in declaration.getOverriddenDeclarations(false)) { - val previousSymbol = put(overridden.symbol, declaration.symbol) - if (previousSymbol != null) { - val previous = previousSymbol.owner as IrDeclaration - error( - "Multiple overrides in class ${irClass.fqNameWhenAvailable} for ${overridden.render()}:\n" + - " previous: ${previous.render()}\n" + - " declared in ${previous.parentAsClass.fqNameWhenAvailable}\n" + - " new: ${declaration.render()}\n" + - " declared in ${declaration.parentAsClass.fqNameWhenAvailable}" - ) - } - } - } - - private fun rebuildClassFakeOverrides(irClass: IrClass) { - if (irClass is IrLazyDeclarationBase) return - if (!processedClasses.add(irClass)) return - val oldList = removedFakeOverrides[irClass.symbol] ?: return - for (c in irClass.superTypes) { - c.getClass()?.let { rebuildClassFakeOverrides(it) } - } - fakeOverrideBuilder.buildFakeOverridesForClass(irClass, false) - - val overriddenMap = mutableMapOf() - - for (declaration in irClass.declarations) { - when (declaration) { - is IrSimpleFunction -> overriddenMap.processDeclaration(declaration, irClass) - is IrProperty -> { - overriddenMap.processDeclaration(declaration, irClass) - declaration.getter?.let { overriddenMap.processDeclaration(it, irClass) } - declaration.setter?.let { overriddenMap.processDeclaration(it, irClass) } - } - } - } - - for (old in oldList) { - val overridden = mutableSetOf>() - collectOverriddenDeclarations(old.owner as IrOverridableDeclaration<*>, overridden, hashSetOf(), true) - val newSymbols = overridden.mapTo(newHashSetWithExpectedSize(1)) { - overriddenMap[it.symbol] - ?: error("No new fake override recorded for declaration in class ${irClass.fqNameWhenAvailable}: ${it.render()}") - } - when (newSymbols.size) { - 0 -> error("No overridden found for declaration in class ${irClass.fqNameWhenAvailable}: ${old.owner.render()}") - 1 -> fakeOverrideMap[old] = newSymbols.single() - else -> error( - "Multiple overridden found for declaration in class ${irClass.fqNameWhenAvailable}: ${old.owner.render()}\n" + - newSymbols.joinToString("\n") { - " - ${it.owner.render()} (declared in ${(it.owner as IrDeclaration).parentAsClass.fqNameWhenAvailable}" - } - ) - } - } - } -} - -private class RemoveFakeOverridesVisitor( - val removedOverrides: MutableMap>, - val symbolTable: SymbolTable -) : IrElementVisitorVoid { - - override fun visitElement(element: IrElement) { - element.acceptChildrenVoid(this) - } - - @OptIn(DelicateSymbolTableApi::class) - override fun visitClass(declaration: IrClass) { - val curList = mutableListOf() - declaration.declarations.removeIf { - if (it is IrOverridableDeclaration<*> && it.isFakeOverride) { - when (it) { - is IrProperty -> { - curList.add(it.symbol) - symbolTable.removeProperty(it.symbol) - it.getter?.symbol?.let { getter -> - curList.add(getter) - symbolTable.removeSimpleFunction(getter) - } - it.setter?.symbol?.let { setter -> - curList.add(setter) - symbolTable.removeSimpleFunction(setter) - } - } - is IrSimpleFunction -> { - curList.add(it.symbol) - symbolTable.removeSimpleFunction(it.symbol) - } - else -> shouldNotBeCalled("Only simple functions and properties can be overridden") - } - true - } else { - false - } - } - if (curList.isNotEmpty()) { - removedOverrides[declaration.symbol] = curList - } - declaration.acceptChildrenVoid(this) - } -} - - -// TODO: KT-61561 it seems this class is too generic to be here. -// For some reason, we don't have utility class doing that, but we probably should, as we have DeepCopy util classes -// Probably, it should also be generated, to avoid missing some places where symbols can happen. -private class RemapFakeOverridesVisitor(val fakeOverridesMap: Map) : IrElementVisitorVoid { - override fun visitElement(element: IrElement) { - element.acceptChildrenVoid(this) - } - - override fun visitSimpleFunction(declaration: IrSimpleFunction) { - declaration.overriddenSymbols = declaration.overriddenSymbols.map { it.remap() } - declaration.acceptChildrenVoid(this) - } - - override fun visitProperty(declaration: IrProperty) { - declaration.overriddenSymbols = declaration.overriddenSymbols.map { it.remap() } - declaration.acceptChildrenVoid(this) - } - - override fun visitCall(expression: IrCall) { - expression.symbol = expression.symbol.remap() - expression.acceptChildrenVoid(this) - } - - override fun visitFunctionReference(expression: IrFunctionReference) { - expression.symbol = expression.symbol.remap() - expression.reflectionTarget = expression.reflectionTarget?.remap() - expression.acceptChildrenVoid(this) - } - - override fun visitPropertyReference(expression: IrPropertyReference) { - expression.symbol = expression.symbol.remap() - expression.getter = expression.getter?.remap() - expression.setter = expression.setter?.remap() - expression.acceptChildrenVoid(this) - } - - override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference) { - expression.getter = expression.getter.remap() - expression.setter = expression.setter?.remap() - expression.acceptChildrenVoid(this) - } - - private inline fun S.remap(): S = - fakeOverridesMap[this] as S? ?: this -} diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrFakeOverrideBuilder.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrFakeOverrideBuilder.kt index 8351297eb55..e6fac575419 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrFakeOverrideBuilder.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrFakeOverrideBuilder.kt @@ -8,7 +8,9 @@ package org.jetbrains.kotlin.ir.overrides import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibility import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyDeclarationBase import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol @@ -16,6 +18,9 @@ import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.collectAndFilterRealOverrides import org.jetbrains.kotlin.ir.util.fileOrNull import org.jetbrains.kotlin.ir.util.render +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.TypeCheckerState @@ -515,3 +520,27 @@ fun IrDeclaration.isOverridableMemberOrAccessor(): Boolean = when (this) { is IrProperty -> isOverridableProperty() else -> false } + +fun IrFakeOverrideBuilder.buildForAll(modules: List) { + val builtFakeOverridesClasses = mutableSetOf() + fun buildFakeOverrides(clazz: IrClass) { + if (clazz is IrLazyDeclarationBase) return + if (!builtFakeOverridesClasses.add(clazz)) return + for (c in clazz.superTypes) { + c.getClass()?.let { buildFakeOverrides(it) } + } + buildFakeOverridesForClass(clazz, false) + } + class ClassVisitor : IrElementVisitorVoid { + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + override fun visitClass(declaration: IrClass) { + buildFakeOverrides(declaration) + declaration.acceptChildrenVoid(this) + } + } + for (module in modules) { + module.acceptVoid(ClassVisitor()) + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/multiplatform/hmpp/simple.kt b/compiler/testData/codegen/box/multiplatform/hmpp/simple.kt index 11228af140a..ddcd9c537f9 100644 --- a/compiler/testData/codegen/box/multiplatform/hmpp/simple.kt +++ b/compiler/testData/codegen/box/multiplatform/hmpp/simple.kt @@ -5,7 +5,6 @@ // WITH_STDLIB // !LANGUAGE: +MultiPlatformProjects -// IGNORE_CODEGEN_WITH_IR_FAKE_OVERRIDE_GENERATION: KT-62535 // TARGET_BACKEND: JVM // MODULE: common // TARGET_PLATFORM: Common diff --git a/compiler/testData/codegen/box/multiplatform/k2/basic/expectInterfaceInSupertypes.kt b/compiler/testData/codegen/box/multiplatform/k2/basic/expectInterfaceInSupertypes.kt index 04b1457ecfe..05dc206d8c4 100644 --- a/compiler/testData/codegen/box/multiplatform/k2/basic/expectInterfaceInSupertypes.kt +++ b/compiler/testData/codegen/box/multiplatform/k2/basic/expectInterfaceInSupertypes.kt @@ -1,6 +1,5 @@ // WITH_STDLIB // LANGUAGE: +MultiPlatformProjects -// IGNORE_CODEGEN_WITH_IR_FAKE_OVERRIDE_GENERATION: KT-62535 // MODULE: common // TARGET_PLATFORM: Common // FILE: common.kt diff --git a/compiler/testData/codegen/box/multiplatform/k2/basic/expectInterfaceInSupertypes2.kt b/compiler/testData/codegen/box/multiplatform/k2/basic/expectInterfaceInSupertypes2.kt index e5f8168d5a6..946505b2b95 100644 --- a/compiler/testData/codegen/box/multiplatform/k2/basic/expectInterfaceInSupertypes2.kt +++ b/compiler/testData/codegen/box/multiplatform/k2/basic/expectInterfaceInSupertypes2.kt @@ -1,5 +1,4 @@ // WITH_STDLIB -// IGNORE_CODEGEN_WITH_IR_FAKE_OVERRIDE_GENERATION: KT-62535 // LANGUAGE: +MultiPlatformProjects // MODULE: common