From bf9cae6410c9bad238da947612521d903dee36f9 Mon Sep 17 00:00:00 2001 From: Pavel Kunyavskiy Date: Tue, 1 Aug 2023 14:59:37 +0200 Subject: [PATCH] [Fir2Ir] Support rebuilding fake overrides over IR ^KT-61514 --- .../fir/components/KtFirCompilerFacility.kt | 3 +- .../kotlin/fir/pipeline/convertToIr.kt | 18 +- .../kotlin/fir/backend/Fir2IrConfiguration.kt | 3 + .../kotlin/fir/backend/Fir2IrConverter.kt | 23 +- compiler/ir/backend.common/build.gradle.kts | 1 + .../actualizer/FakeOverrideRebuilder.kt | 251 ++++++++++++++++++ .../backend/common/actualizer/IrActualizer.kt | 39 ++- .../ir/IrActualizerAndPluginsFacade.kt | 8 +- .../frontend/fir/Fir2IrJsResultsConverter.kt | 4 +- .../frontend/fir/Fir2IrJvmResultsConverter.kt | 6 +- .../fir/Fir2IrWasmResultsConverter.kt | 4 +- .../kotlin/codegen/GenerationUtils.kt | 4 +- 12 files changed, 340 insertions(+), 24 deletions(-) create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/FakeOverrideRebuilder.kt diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt index f14f44d0241..69779a2a3f0 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt @@ -159,7 +159,8 @@ internal class KtFirCompilerFacility( Fir2IrJvmSpecialAnnotationSymbolProvider(), DefaultBuiltIns.Instance, Fir2IrCommonMemberStorage(signatureComposerForJvmFir2Ir(false), FirJvmKotlinMangler()), - initializedIrBuiltIns = null + initializedIrBuiltIns = null, + ::JvmIrTypeSystemContext, ) patchCodeFragmentIr(fir2IrResult) 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 ead74cde459..4239816d09f 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 @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.backend.jvm.Fir2IrJvmSpecialAnnotationSymbolProv import org.jetbrains.kotlin.fir.backend.jvm.FirJvmKotlinMangler import org.jetbrains.kotlin.fir.backend.jvm.FirJvmVisibilityConverter import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.fir.moduleData import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmDescriptorMangler @@ -44,6 +45,7 @@ data class ModuleCompilerAnalyzedOutput( irMangler: KotlinMangler.IrMangler, visibilityConverter: Fir2IrVisibilityConverter, kotlinBuiltIns: KotlinBuiltIns, + typeContextProvider: (IrBuiltIns) -> IrTypeSystemContext, ): Fir2IrResult { return Fir2IrConverter.createIrModuleFragment( session, scopeSession, fir, @@ -52,7 +54,8 @@ data class ModuleCompilerAnalyzedOutput( Fir2IrJvmSpecialAnnotationSymbolProvider(), // TODO KT-60526: replace with appropriate (probably empty) implementation for other backends. kotlinBuiltIns = kotlinBuiltIns, commonMemberStorage = commonMemberStorage, - initializedIrBuiltIns = irBuiltIns + initializedIrBuiltIns = irBuiltIns, + typeContextProvider = typeContextProvider ) } } @@ -117,6 +120,7 @@ fun FirResult.convertToIrAndActualize( irMangler, visibilityConverter, kotlinBuiltIns, + actualizerTypeContextProvider, ).also { result -> fir2IrResultPostCompute(result) } @@ -129,12 +133,15 @@ fun FirResult.convertToIrAndActualize( val commonIrOutputs = commonOutputs.map { it.convertToIr( fir2IrExtensions, - fir2IrConfiguration, + // We need to build all modules before rebuilding fake overrides + // to avoid fixing declaration storages + fir2IrConfiguration.copy(useIrFakeOverrideBuilder = false), commonMemberStorage = commonMemberStorage, irBuiltIns = irBuiltIns, irMangler, visibilityConverter, kotlinBuiltIns, + actualizerTypeContextProvider, ).also { result -> fir2IrResultPostCompute(result) if (irBuiltIns == null) { @@ -150,6 +157,7 @@ fun FirResult.convertToIrAndActualize( irMangler, visibilityConverter, kotlinBuiltIns, + actualizerTypeContextProvider, ).also { fir2IrResultPostCompute(it) } @@ -159,7 +167,11 @@ fun FirResult.convertToIrAndActualize( commonIrOutputs.map { it.irModuleFragment }, fir2IrConfiguration.diagnosticReporter, actualizerTypeContextProvider(fir2IrResult.irModuleFragment.irBuiltins), - fir2IrConfiguration.languageVersionSettings + fir2IrConfiguration.languageVersionSettings, + commonMemberStorage.symbolTable, + irMangler, + Fir2IrConverter.friendModulesMap(outputs.last().session), + fir2IrConfiguration.useIrFakeOverrideBuilder ) } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConfiguration.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConfiguration.kt index 044b0602e16..bd1d405ebd2 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConfiguration.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConfiguration.kt @@ -27,6 +27,8 @@ import org.jetbrains.kotlin.incremental.components.InlineConstTracker * It means asking for an IR element of a non-cached declaration is a sign of inconsistent state. * Code generation in the IDE is trickier, though, as declarations from any module can be potentially referenced. * For such a scenario, there is a flag that relaxes consistency checks. + * + * @param useIrFakeOverrideBuilder enables creation of fake-overrides using IR f/o generator instead of FIR2IR one. KT-61514 */ data class Fir2IrConfiguration( val languageVersionSettings: LanguageVersionSettings, @@ -35,4 +37,5 @@ data class Fir2IrConfiguration( val evaluatedConstTracker: EvaluatedConstTracker, val inlineConstTracker: InlineConstTracker?, val allowNonCachedDeclarations: Boolean, + val useIrFakeOverrideBuilder: Boolean = false ) 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 c4e3cea1995..123aeb5f3bd 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 @@ -10,6 +10,7 @@ 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.backend.common.actualizer.FakeOverrideRebuilder import org.jetbrains.kotlin.backend.common.sourceElement import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.config.LanguageFeature @@ -30,6 +31,7 @@ import org.jetbrains.kotlin.fir.extensions.generatedNestedClassifiers import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.symbols.lazyDeclarationResolver import org.jetbrains.kotlin.ir.PsiIrFileEntry +import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl @@ -40,6 +42,7 @@ import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode import org.jetbrains.kotlin.ir.interpreter.transformer.transformConst +import org.jetbrains.kotlin.ir.types.IrTypeSystemContext import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorPublicSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionPublicSymbolImpl import org.jetbrains.kotlin.ir.util.KotlinMangler @@ -530,6 +533,13 @@ class Fir2IrConverter( } } + // TODO: drop this function in favor of using [IrModuleDescriptor::shouldSeeInternalsOf] in FakeOverrideBuilder KT-61384 + fun friendModulesMap(session: FirSession) = mapOf( + session.moduleData.name.asStringStripSpecialMarkers() to session.moduleData.friendDependencies.map { + it.name.asStringStripSpecialMarkers() + } + ) + fun createIrModuleFragment( session: FirSession, scopeSession: ScopeSession, @@ -542,7 +552,8 @@ class Fir2IrConverter( specialSymbolProvider: Fir2IrSpecialSymbolProvider, kotlinBuiltIns: KotlinBuiltIns, commonMemberStorage: Fir2IrCommonMemberStorage, - initializedIrBuiltIns: IrBuiltInsOverFir? + initializedIrBuiltIns: IrBuiltInsOverFir?, + typeContextProvider: (IrBuiltIns) -> IrTypeSystemContext ): Fir2IrResult { session.lazyDeclarationResolver.disableLazyResolveContractChecks() val moduleDescriptor = FirModuleDescriptor(session, kotlinBuiltIns) @@ -564,6 +575,16 @@ class Fir2IrConverter( allFirFiles, irModuleFragment, components.fir2IrVisitor, runPreCacheBuiltinClasses = initializedIrBuiltIns == null ) + if (fir2IrConfiguration.useIrFakeOverrideBuilder) { + FakeOverrideRebuilder( + commonMemberStorage.symbolTable, + irMangler, + typeContextProvider(components.irBuiltIns), + irModuleFragment, + friendModulesMap(session) + ).rebuildFakeOverrides() + } + return Fir2IrResult(irModuleFragment, components, moduleDescriptor) } } diff --git a/compiler/ir/backend.common/build.gradle.kts b/compiler/ir/backend.common/build.gradle.kts index 536821df6b0..bf1f467700c 100644 --- a/compiler/ir/backend.common/build.gradle.kts +++ b/compiler/ir/backend.common/build.gradle.kts @@ -9,6 +9,7 @@ dependencies { api(project(":compiler:backend-common")) api(project(":compiler:ir.tree")) api(project(":compiler:ir.interpreter")) + implementation(project(":compiler:ir.serialization.common")) compileOnly(intellijCore()) } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/FakeOverrideRebuilder.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/FakeOverrideRebuilder.kt new file mode 100644 index 00000000000..52216af7b95 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/FakeOverrideRebuilder.kt @@ -0,0 +1,251 @@ +/* + * 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.backend.common.linkage.partial.PartialLinkageSupportForLinker +import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder +import org.jetbrains.kotlin.backend.common.overrides.FileLocalAwareLinker +import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +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.* +import org.jetbrains.kotlin.ir.symbols.impl.IrPropertySymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl +import org.jetbrains.kotlin.ir.types.IrTypeSystemContext +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.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled + + +/** + * 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 untrivial than just substitute expect class with actual. + * + * For example, if an expect class is actualized to common class, or several expect classes are actualized to 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 stretch, after actualization is done. + * + * This is done in 3 steps: + * 1. Remove all fake overrides from all classes + * 2. Build new fake overrides and map old one to some function now existing in class (possible real function, not fake override) + * 3. Remap callsites of all functions using the map collected on step 2. + * + * Steps 1 and 3 are kinda trivial, expect we should remove all fake overrides from symbol table. + * + * For matching in step 2, classes are processed in such order. That superclass is processed before class. + * That allows us to match using overridden symbols. In particular, f/o is mapped to only function + * overriding any of functions (possibly already mapped), which was overriden by initial fake override. + * + * Here we assume that functions can be only 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 mangler: KotlinMangler.IrMangler, + val typeSystemContext: IrTypeSystemContext, + val irModule: IrModuleFragment, + // TODO: drop this argument in favor of using [IrModuleDescriptor::shouldSeeInternalsOf] in FakeOverrideBuilder KT-61384 + friendModules: Map> +) { + private val removedFakeOverrides = mutableMapOf>() + private val processedClasses = mutableSetOf() + private val fakeOverrideMap = mutableMapOf() + + private val fakeOverrideBuilder = FakeOverrideBuilder( + LocalFakeOverridesStorage(), + symbolTable, + mangler, + typeSystemContext, + friendModules, + PartialLinkageSupportForLinker.DISABLED + ) + + fun rebuildFakeOverrides() { + 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 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.provideFakeOverrides(irClass, CompatibilityMode.CURRENT) + val overriddenMap = mutableMapOf() + irClass.properties + .forEach { prop -> + val allOverridden = mutableSetOf>() + collectOverriddenDeclarations(prop, allOverridden, mutableSetOf(), false) + for (overridden in allOverridden) { + require(overriddenMap.put(overridden.symbol, prop.symbol) == null) { "Multiple overrides for ${overridden.render()} "} + } + } + irClass.simpleFunctions() + .forEach { func -> + val allOverridden = mutableSetOf>() + collectOverriddenDeclarations(func, allOverridden, mutableSetOf(), false) + for (overridden in allOverridden) { + require(overriddenMap.put(overridden.symbol, func.symbol) == null) { "Multiple overrides for ${overridden.render()} "} + } + } + for (old in oldList) { + fakeOverrideMap[old] = mutableSetOf>() + .apply { collectOverriddenDeclarations(old.owner as IrOverridableDeclaration<*>, this, mutableSetOf(), true) } + .map { overriddenMap[it.symbol] } + .distinct() + .single() ?: error("${old.owner.render()} is not overridden in ${irClass.render()}") + } + } +} + +private class LocalFakeOverridesStorage : FileLocalAwareLinker { + val funStorage = mutableMapOf, IrSimpleFunctionSymbolImpl>() + val propertyStorage = mutableMapOf, IrPropertySymbol>() + override fun tryReferencingSimpleFunctionByLocalSignature( + parent: IrDeclaration, + idSignature: IdSignature, + ): IrSimpleFunctionSymbol? { + if (idSignature.isPubliclyVisible) return null + return funStorage.getOrPut(parent to idSignature) { + IrSimpleFunctionSymbolImpl() + } + } + + override fun tryReferencingPropertyByLocalSignature(parent: IrDeclaration, idSignature: IdSignature): IrPropertySymbol? { + if (idSignature.isPubliclyVisible) return null + return propertyStorage.getOrPut(parent to idSignature) { + IrPropertySymbolImpl() + } + } +} + +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 seams, this class is too generic to be here. +// By 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 plaves, 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 { + (fakeOverridesMap[it] as? IrSimpleFunctionSymbol) ?: it + } + declaration.acceptChildrenVoid(this) + } + + override fun visitProperty(declaration: IrProperty) { + declaration.overriddenSymbols = declaration.overriddenSymbols.map { + (fakeOverridesMap[it] as? IrPropertySymbol) ?: it + } + declaration.acceptChildrenVoid(this) + } + + override fun visitCall(expression: IrCall) { + expression.symbol = (fakeOverridesMap[expression.symbol] as? IrSimpleFunctionSymbol) ?: expression.symbol + expression.acceptChildrenVoid(this) + } + + override fun visitFunctionReference(expression: IrFunctionReference) { + expression.symbol = (fakeOverridesMap[expression.symbol] as? IrSimpleFunctionSymbol) ?: expression.symbol + expression.acceptChildrenVoid(this) + } + + override fun visitPropertyReference(expression: IrPropertyReference) { + expression.symbol = (fakeOverridesMap[expression.symbol] as? IrPropertySymbol) ?: expression.symbol + expression.getter = (expression.getter?.let { fakeOverridesMap[it] } as? IrSimpleFunctionSymbol) ?: expression.getter + expression.setter = (expression.setter?.let { fakeOverridesMap[it] } as? IrSimpleFunctionSymbol) ?: expression.setter + expression.acceptChildrenVoid(this) + } + + override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference) { + expression.getter = (fakeOverridesMap[expression.getter] as? IrSimpleFunctionSymbol) ?: expression.getter + expression.setter = (expression.setter?.let { fakeOverridesMap[it] } as? IrSimpleFunctionSymbol) ?: expression.setter + expression.acceptChildrenVoid(this) + } +} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/IrActualizer.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/IrActualizer.kt index 1ad15cb11b5..1d68b341d67 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/IrActualizer.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/actualizer/IrActualizer.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.types.IrTypeSystemContext -import org.jetbrains.kotlin.ir.util.DeepCopyTypeRemapper +import org.jetbrains.kotlin.ir.util.* data class IrActualizedResult(val actualizedExpectDeclarations: List) @@ -21,7 +21,12 @@ object IrActualizer { dependentFragments: List, diagnosticReporter: DiagnosticReporter, typeSystemContext: IrTypeSystemContext, - languageVersionSettings: LanguageVersionSettings + languageVersionSettings: LanguageVersionSettings, + symbolTable: SymbolTable, + mangler: KotlinMangler.IrMangler, + // TODO: drop this argument in favor of using [IrModuleDescriptor::shouldSeeInternalsOf] in FakeOverrideBuilder KT-61384 + friendModules: Map>, + useIrFakeOverrideBuilder: Boolean ): IrActualizedResult { val ktDiagnosticReporter = KtDiagnosticReporterWithImplicitIrBasedContext(diagnosticReporter, languageVersionSettings) @@ -40,18 +45,20 @@ object IrActualizer { // Also, it doesn't remove unactualized expect declarations marked with @OptionalExpectation val removedExpectDeclarations = removeExpectDeclarations(dependentFragments, expectActualMap) - // 3. Actualize expect fake overrides in non-expect classes inside common or multi-platform module. - // It's probably important to run FakeOverridesActualizer before ActualFakeOverridesAdder - FakeOverridesActualizer(expectActualMap).apply { dependentFragments.forEach { visitModuleFragment(it) } } + if (!useIrFakeOverrideBuilder) { + // 3. Actualize expect fake overrides in non-expect classes inside common or multi-platform module. + // It's probably important to run FakeOverridesActualizer before ActualFakeOverridesAdder + FakeOverridesActualizer(expectActualMap).apply { dependentFragments.forEach { visitModuleFragment(it) } } - // 4. Add fake overrides to non-expect classes inside common or multi-platform module, - // taken from these non-expect classes actualized super classes. - ActualFakeOverridesAdder( - expectActualMap, - actualDeclarations.actualClasses, - ktDiagnosticReporter, - typeSystemContext - ).apply { dependentFragments.forEach { visitModuleFragment(it) } } + // 4. Add fake overrides to non-expect classes inside common or multi-platform module, + // taken from these non-expect classes actualized super classes. + ActualFakeOverridesAdder( + expectActualMap, + actualDeclarations.actualClasses, + ktDiagnosticReporter, + typeSystemContext + ).apply { dependentFragments.forEach { visitModuleFragment(it) } } + } // 5. Copy and actualize function parameter default values from expect functions val symbolRemapper = ActualizerSymbolRemapper(expectActualMap) @@ -65,6 +72,11 @@ object IrActualizer { // 7. Merge dependent fragments into the main one mergeIrFragments(mainFragment, dependentFragments) + if (useIrFakeOverrideBuilder) { + // 8. Rebuild fake overrides from stretch, as they could become invalid during actualization + FakeOverrideRebuilder(symbolTable, mangler, typeSystemContext, mainFragment, friendModules).rebuildFakeOverrides() + } + return IrActualizedResult(removedExpectDeclarations) } @@ -98,3 +110,4 @@ object IrActualizer { mainFragment.files.addAll(0, dependentFragments.flatMap { it.files }) } } + diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/IrActualizerAndPluginsFacade.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/IrActualizerAndPluginsFacade.kt index 8378c690b41..8743298759c 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/IrActualizerAndPluginsFacade.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/IrActualizerAndPluginsFacade.kt @@ -12,7 +12,9 @@ import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.fir.pipeline.applyIrGenerationExtensions import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl +import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.platform.jvm.isJvm +import org.jetbrains.kotlin.test.directives.CodegenTestDirectives import org.jetbrains.kotlin.test.model.* import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.compilerConfigurationProvider @@ -33,7 +35,11 @@ class IrActualizerAndPluginsFacade( inputArtifact.dependentIrModuleFragments, inputArtifact.diagnosticReporter, typeSystemContext, - testServices.compilerConfigurationProvider.getCompilerConfiguration(module).languageVersionSettings + testServices.compilerConfigurationProvider.getCompilerConfiguration(module).languageVersionSettings, + inputArtifact.irPluginContext.symbolTable as SymbolTable, // TODO: it's strange place to get it. + inputArtifact.irMangler, + mapOf(module.name to module.friendDependencies.map { it.moduleName }), + useIrFakeOverrideBuilder = false, ) inputArtifact.irActualizerResult = result } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJsResultsConverter.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJsResultsConverter.kt index c0c3ee4161d..f737b589126 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJsResultsConverter.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJsResultsConverter.kt @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.ir.backend.js.incrementalDataProvider import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary import org.jetbrains.kotlin.library.unresolvedDependencies import org.jetbrains.kotlin.storage.LockBasedStorageManager @@ -180,7 +181,8 @@ fun ModuleCompilerAnalyzedOutput.convertToJsIr( irBuiltIns, JsManglerIr, Fir2IrVisibilityConverter.Default, - builtIns ?: DefaultBuiltIns.Instance // TODO: consider passing externally, + builtIns ?: DefaultBuiltIns.Instance, // TODO: consider passing externally, + ::IrTypeSystemContextImpl ).also { (it.irModuleFragment.descriptor as? FirModuleDescriptor)?.let { it.allDependencyModules = dependencies } } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJvmResultsConverter.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJvmResultsConverter.kt index b3ba59dfdc1..32db00d60e4 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJvmResultsConverter.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJvmResultsConverter.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.test.frontend.fir import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory import org.jetbrains.kotlin.backend.jvm.JvmIrDeserializerImpl +import org.jetbrains.kotlin.backend.jvm.JvmIrTypeSystemContext import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.jvm.compiler.NoScopeRecordCliBindingTrace @@ -113,8 +114,9 @@ class Fir2IrJvmResultsConverter( irBuiltIns, irMangler, FirJvmVisibilityConverter, - DefaultBuiltIns.Instance - ) + DefaultBuiltIns.Instance, + typeContextProvider = ::JvmIrTypeSystemContext, + ) irBuiltIns = components.irBuiltIns if (index < inputArtifact.partsForDependsOnModules.size - 1) { diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrWasmResultsConverter.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrWasmResultsConverter.kt index 6d211d92200..833de1d065f 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrWasmResultsConverter.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrWasmResultsConverter.kt @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.ir.backend.js.incrementalDataProvider import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary import org.jetbrains.kotlin.library.unresolvedDependencies import org.jetbrains.kotlin.storage.LockBasedStorageManager @@ -176,7 +177,8 @@ fun ModuleCompilerAnalyzedOutput.convertToWasmIr( irBuiltIns, JsManglerIr, Fir2IrVisibilityConverter.Default, - builtIns ?: DefaultBuiltIns.Instance // TODO: consider passing externally, + builtIns ?: DefaultBuiltIns.Instance, // TODO: consider passing externally + typeContextProvider = ::IrTypeSystemContextImpl, ).also { (it.irModuleFragment.descriptor as? FirModuleDescriptor)?.let { it.allDependencyModules = dependencies } } diff --git a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/GenerationUtils.kt b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/GenerationUtils.kt index 63399c4f09c..4d63c65b8a4 100644 --- a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/GenerationUtils.kt +++ b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/codegen/GenerationUtils.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.analyzer.AnalysisResult import org.jetbrains.kotlin.asJava.finder.JavaElementFinder import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory import org.jetbrains.kotlin.backend.jvm.JvmIrDeserializerImpl +import org.jetbrains.kotlin.backend.jvm.JvmIrTypeSystemContext import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity @@ -149,7 +150,8 @@ object GenerationUtils { irBuiltIns = null, JvmIrMangler, FirJvmVisibilityConverter, - DefaultBuiltIns.Instance + DefaultBuiltIns.Instance, + ::JvmIrTypeSystemContext ) val dummyBindingContext = NoScopeRecordCliBindingTrace().bindingContext