[FIR2IR] Rework actualization pipeline

There are a lot of restrictions between different parts of the pipeline.

1. Fake overrides can't be built before classes are actualized
2. Constants can't be evaluated before callables are actualized
3. Callables can't be actulaized before fake overrides are built
4. Checkers can't run before constants are evaluated

This commit reorders things to make all these restrictions happy.

^KT-63644
This commit is contained in:
Pavel Kunyavskiy
2023-11-23 15:44:35 +01:00
committed by Space Team
parent 9609ac6908
commit c485382e80
9 changed files with 144 additions and 366 deletions
@@ -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<ModuleCompilerAnalyzedOutput>)
@@ -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)
}