From dcd3f3b1557c3d87091777cb7e6fc7ed2f4cfb6d Mon Sep 17 00:00:00 2001 From: Pavel Kunyavskiy Date: Thu, 23 Nov 2023 15:50:43 +0100 Subject: [PATCH] [FIR2IR] Replace fake override symbols with normal ones Fir2Ir introduces temporary symbols to avoid creating fake overrides themselves. Further pipeline is not ready to these symbols. That's why we have introduced separate pass, that replaces all this symbols with real fake override symbols, after they are created. ^KT-63645 --- .../kotlin/fir/pipeline/convertToIr.kt | 6 + .../SpecialFakeOverrideSymbolsResolver.kt | 155 ++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 compiler/ir/ir.actualization/src/main/kotlin/org/jetbrains/kotlin/backend/common/actualizer/SpecialFakeOverrideSymbolsResolver.kt 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 be5871b59ba..9437c400c4b 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 @@ -8,6 +8,8 @@ package org.jetbrains.kotlin.fir.pipeline import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext import org.jetbrains.kotlin.backend.common.actualizer.IrActualizedResult import org.jetbrains.kotlin.backend.common.actualizer.IrActualizer +import org.jetbrains.kotlin.backend.common.actualizer.SpecialFakeOverrideSymbolsResolver +import org.jetbrains.kotlin.backend.common.actualizer.SpecialFakeOverrideSymbolsResolverVisitor import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor @@ -113,6 +115,10 @@ fun FirResult.convertToIrAndActualize( components.fakeOverrideBuilder.buildForAll(allIrModules) } val expectActualMap = irActualizer?.actualizeCallablesAndMergeModules() ?: emptyMap() + if (components.configuration.useIrFakeOverrideBuilder) { + val fakeOverrideResolver = SpecialFakeOverrideSymbolsResolver(expectActualMap) + irModuleFragment.acceptVoid(SpecialFakeOverrideSymbolsResolverVisitor(fakeOverrideResolver)) + } Fir2IrConverter.evaluateConstants(irModuleFragment, components) val actualizationResult = irActualizer?.runChecksAndFinalize(expectActualMap) pluginContext.applyIrGenerationExtensions(irModuleFragment, irGeneratorExtensions) diff --git a/compiler/ir/ir.actualization/src/main/kotlin/org/jetbrains/kotlin/backend/common/actualizer/SpecialFakeOverrideSymbolsResolver.kt b/compiler/ir/ir.actualization/src/main/kotlin/org/jetbrains/kotlin/backend/common/actualizer/SpecialFakeOverrideSymbolsResolver.kt new file mode 100644 index 00000000000..ef06b01de7b --- /dev/null +++ b/compiler/ir/ir.actualization/src/main/kotlin/org/jetbrains/kotlin/backend/common/actualizer/SpecialFakeOverrideSymbolsResolver.kt @@ -0,0 +1,155 @@ +/* + * 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.backend.common.actualizer + +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.* +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.IrFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.IrSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrFakeOverrideSymbolBase +import org.jetbrains.kotlin.ir.util.SymbolRemapper +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled + +/** + * This class provides utility to resolve [org.jetbrains.kotlin.ir.symbols.impl.IrFunctionFakeOverrideSymbol] + * and [org.jetbrains.kotlin.ir.symbols.impl.IrPropertyFakeOverrideSymbol] to normal symbols. + * + * It can be used after classifiers are actualized and fake overrides are built. + * + * Conceptually, a fake override symbol is a pair of real symbol and class in which we need to find this fake override. + * + * When the first remapping request comes for a class, all its supertypes are traversed recursively and for all declarations inside, + * all overrides are cached. + * + * This approach is quadratic over the height of class hierarchy. Unfortunately, we need all overrides, not only direct ones + * (and not only direct-real ones). Because some intermediate overrides can appear in the process of actualization, + * and we can't guarantee that all real symbols are some specific preferred overrides, as they were right after Fir2Ir. + * + */ +class SpecialFakeOverrideSymbolsResolver(private val expectActualMap: Map) : SymbolRemapper.Empty() { + /** + * Map from (class, declaration) -> declarationInsideClass + * + * Means that declarationInsideClass is the one overriding this declaration in this class. + * [processClass] function add all valid pairs for this class to the map. + */ + private val cachedFakeOverrides = mutableMapOf, IrSymbol>() + private val processedClasses = mutableSetOf() + + override fun getReferencedFunction(symbol: IrFunctionSymbol): IrFunctionSymbol { + return symbol.remap() + } + + override fun getReferencedSimpleFunction(symbol: IrSimpleFunctionSymbol): IrSimpleFunctionSymbol { + return symbol.remap() + } + + override fun getReferencedProperty(symbol: IrPropertySymbol): IrPropertySymbol { + return symbol.remap() + } + + private inline fun S.remap(): S { + if (this !is IrFakeOverrideSymbolBase<*, *, *>) { + return this + } + val actualizedClassSymbol = containingClassSymbol.actualize() + val actualizedOriginalSymbol = originalSymbol.actualize() + processClass(actualizedClassSymbol.owner) + when (val result = cachedFakeOverrides[actualizedClassSymbol to actualizedOriginalSymbol]) { + null -> error("No override for $actualizedOriginalSymbol in $actualizedClassSymbol") + !is S -> error("Override for $actualizedOriginalSymbol in $actualizedClassSymbol has incompatible type: $result") + else -> return result + } + } + + private fun IrClassSymbol.actualize(): IrClassSymbol { + return (this as IrSymbol).actualize() as IrClassSymbol + } + + private fun IrSymbol.actualize(): IrSymbol { + return expectActualMap[this] ?: this + } + + private fun processClass(irClass: IrClass) { + require(!irClass.isExpect) { "There should be no references to expect classes at this point" } + if (!processedClasses.add(irClass)) return + for (declaration in irClass.declarations) { + if (declaration !is IrOverridableDeclaration<*>) continue + processDeclaration(irClass.symbol, declaration) + if (declaration is IrProperty) { + declaration.getter?.let { processDeclaration(irClass.symbol, it) } + declaration.setter?.let { processDeclaration(irClass.symbol, it) } + } + } + } + + private fun processDeclaration(classSymbol: IrClassSymbol, declaration: IrOverridableDeclaration<*>) { + for (overridden in declaration.collectOverrides(mutableSetOf())) { + cachedFakeOverrides[classSymbol to overridden] = declaration.symbol + } + } + + private fun IrOverridableDeclaration<*>.collectOverrides(visited: MutableSet): Sequence = sequence { + if (visited.add(symbol)) { + if (!isFakeOverride) { + yield(symbol) + } + for (overridden in overriddenSymbols) { + yieldAll((overridden.remap().owner as IrOverridableDeclaration<*>).collectOverrides(visited)) + } + } + } +} + + +class SpecialFakeOverrideSymbolsResolverVisitor(private val resolver: SpecialFakeOverrideSymbolsResolver) : IrElementVisitorVoid { + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitSimpleFunction(declaration: IrSimpleFunction) { + declaration.overriddenSymbols = declaration.overriddenSymbols.map(resolver::getReferencedSimpleFunction) + declaration.acceptChildrenVoid(this) + } + + override fun visitProperty(declaration: IrProperty) { + declaration.overriddenSymbols = declaration.overriddenSymbols.map(resolver::getReferencedProperty) + declaration.acceptChildrenVoid(this) + } + + override fun visitCall(expression: IrCall) { + expression.symbol = resolver.getReferencedSimpleFunction(expression.symbol) + expression.acceptChildrenVoid(this) + } + + override fun visitFunctionReference(expression: IrFunctionReference) { + expression.symbol = resolver.getReferencedFunction(expression.symbol) + expression.reflectionTarget = expression.reflectionTarget?.let(resolver::getReferencedFunction) + expression.acceptChildrenVoid(this) + } + + override fun visitPropertyReference(expression: IrPropertyReference) { + expression.symbol = expression.symbol.let(resolver::getReferencedProperty) + expression.getter = expression.getter?.let(resolver::getReferencedSimpleFunction) + expression.setter = expression.setter?.let(resolver::getReferencedSimpleFunction) + expression.acceptChildrenVoid(this) + } + + override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference) { + expression.getter = expression.getter.let(resolver::getReferencedSimpleFunction) + expression.setter = expression.setter?.let(resolver::getReferencedSimpleFunction) + expression.acceptChildrenVoid(this) + } +}