All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.fir.pipeline.convertToIr.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-RC
Show newest version
/*
 * Copyright 2010-2021 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.fir.pipeline

import org.jetbrains.kotlin.backend.common.CodegenUtil
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.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.diagnostics.impl.BaseDiagnosticsCollector
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.backend.jvm.Fir2IrJvmSpecialAnnotationSymbolProvider
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.signaturer.FirBasedSignatureComposer
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.KtDiagnosticReporterWithImplicitIrBasedContext
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyDeclarationBase
import org.jetbrains.kotlin.ir.overrides.IrFakeOverrideBuilder
import org.jetbrains.kotlin.ir.symbols.UnsafeDuringIrConstructionAPI
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.util.KotlinMangler
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.runIf

data class FirResult(val outputs: List)

data class ModuleCompilerAnalyzedOutput(
    val session: FirSession,
    val scopeSession: ScopeSession,
    val fir: List
)

data class Fir2IrActualizedResult(
    val irModuleFragment: IrModuleFragment,
    val components: Fir2IrComponents,
    val pluginContext: Fir2IrPluginContext,
    val irActualizedResult: IrActualizedResult?,
)

fun List.runPlatformCheckers(reporter: BaseDiagnosticsCollector) {
    val platformModule = this.last()
    val session = platformModule.session
    val scopeSession = platformModule.scopeSession

    val allFiles = this.flatMap { it.fir }
    session.runCheckers(scopeSession, allFiles, reporter, MppCheckerKind.Platform)
}

fun FirResult.convertToIrAndActualize(
    fir2IrExtensions: Fir2IrExtensions,
    fir2IrConfiguration: Fir2IrConfiguration,
    irGeneratorExtensions: Collection,
    irMangler: KotlinMangler.IrMangler,
    firMangler: FirMangler,
    visibilityConverter: Fir2IrVisibilityConverter,
    kotlinBuiltIns: KotlinBuiltIns,
    actualizerTypeContextProvider: (IrBuiltIns) -> IrTypeSystemContext,
    fir2IrResultPostCompute: (ModuleCompilerAnalyzedOutput, Fir2IrResult) -> Unit = { _, _ -> },
): Fir2IrActualizedResult {
    val commonMemberStorage = Fir2IrCommonMemberStorage(FirBasedSignatureComposer.create(firMangler, fir2IrConfiguration))

    require(outputs.isNotEmpty()) { "No modules found" }

    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) = 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.useFirBasedFakeOverrideGenerator,
        irModuleFragment,
        allIrModules.dropLast(1),
    )

    if (!fir2IrConfiguration.useFirBasedFakeOverrideGenerator) {
        // 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()
        val temporaryResolver = SpecialFakeOverrideSymbolsResolver(emptyMap())
        components.fakeOverrideBuilder.buildForAll(allIrModules, temporaryResolver)
    }
    val expectActualMap = irActualizer?.actualizeCallablesAndMergeModules() ?: emptyMap()
    val fakeOverrideResolver = runIf(!components.configuration.useFirBasedFakeOverrideGenerator) {
        val fakeOverrideResolver = SpecialFakeOverrideSymbolsResolver(expectActualMap)
        irModuleFragment.acceptVoid(SpecialFakeOverrideSymbolsResolverVisitor(fakeOverrideResolver))
        @OptIn(Fir2IrSymbolsMappingForLazyClasses.SymbolRemapperInternals::class)
        components.symbolsMappingForLazyClasses.initializeSymbolMap(fakeOverrideResolver)
        fakeOverrideResolver
    }
    Fir2IrConverter.evaluateConstants(irModuleFragment, components)
    val actualizationResult = irActualizer?.runChecksAndFinalize(expectActualMap)

    fakeOverrideResolver?.cacheFakeOverridesOfAllClasses(irModuleFragment)

    pluginContext.applyIrGenerationExtensions(irModuleFragment, irGeneratorExtensions)
    return Fir2IrActualizedResult(irModuleFragment, components, pluginContext, actualizationResult)
}


private fun resolveOverridenSymbolsInLazyClass(
    clazz: Fir2IrLazyClass,
    resolver: SpecialFakeOverrideSymbolsResolver
) {
    /*
     * Eventually, we should be able to process lazy classes with the same code.
     *
     * Now we can't do this, because overriding by Java function is not supported correctly in IR builder.
     * In most cases, nothing need to be done for lazy classes. For other cases, it is
     * caller responsibility to handle them.
     *
     * Super-classes already have processed fake overrides at this moment.
     * Also, all Fir2IrLazyClass super-classes are always platform classes,
     * so it's valid to process it with empty expect-actual mapping.
     *
     * But this is still a hack, and should be removed within KT-64352
     */
    @OptIn(UnsafeDuringIrConstructionAPI::class)
    for (declaration in clazz.declarations) {
        when (declaration) {
            is IrSimpleFunction -> {
                declaration.overriddenSymbols = declaration.overriddenSymbols.map { resolver.getReferencedSimpleFunction(it) }
            }
            is IrProperty -> {
                declaration.overriddenSymbols = declaration.overriddenSymbols.map { resolver.getReferencedProperty(it) }
                declaration.getter?.let { getter ->
                    getter.overriddenSymbols = getter.overriddenSymbols.map { resolver.getReferencedSimpleFunction(it) }
                }
                declaration.setter?.let { setter ->
                    setter.overriddenSymbols = setter.overriddenSymbols.map { resolver.getReferencedSimpleFunction(it) }
                }
            }
        }
    }
}

private fun IrFakeOverrideBuilder.buildForAll(
    modules: List,
    resolver: SpecialFakeOverrideSymbolsResolver
) {
    val builtFakeOverridesClasses = mutableSetOf()
    fun buildFakeOverrides(clazz: IrClass) {
        if (!builtFakeOverridesClasses.add(clazz)) return
        for (c in clazz.superTypes) {
            c.getClass()?.let { buildFakeOverrides(it) }
        }
        if (clazz is IrLazyDeclarationBase) {
            resolveOverridenSymbolsInLazyClass(clazz as Fir2IrLazyClass, resolver)
        } else {
            buildFakeOverridesForClass(clazz, false)
        }
    }

    class ClassVisitor : IrElementVisitorVoid {
        override fun visitElement(element: IrElement) {
            element.acceptChildrenVoid(this)
        }

        private fun isIgnoredClass(declaration: IrClass) : Boolean {
            return when {
                declaration.isExpect -> true
                declaration.metadata is MetadataSource.CodeFragment -> true
                else -> false
            }
        }

        override fun visitClass(declaration: IrClass) {
            if (!isIgnoredClass(declaration)) {
                buildFakeOverrides(declaration)
            }
            declaration.acceptChildrenVoid(this)
        }
    }

    for (module in modules) {
        for (file in module.files) {
            try {
                file.acceptVoid(ClassVisitor())
            } catch (e: Throwable) {
                CodegenUtil.reportBackendException(e, "IR fake override builder", file.fileEntry.name) { offset ->
                    file.fileEntry.takeIf { it.supportsDebugInfo }?.let {
                        val (line, column) = it.getLineAndColumnNumbers(offset)
                        line to column
                    }
                }
            }
        }
    }
}

private fun convertToIr(
    firOutput: ModuleCompilerAnalyzedOutput,
    fir2IrExtensions: Fir2IrExtensions,
    fir2IrConfiguration: Fir2IrConfiguration,
    commonMemberStorage: Fir2IrCommonMemberStorage,
    irBuiltIns: IrBuiltInsOverFir?,
    irMangler: KotlinMangler.IrMangler,
    visibilityConverter: Fir2IrVisibilityConverter,
    kotlinBuiltIns: KotlinBuiltIns,
    typeContextProvider: (IrBuiltIns) -> IrTypeSystemContext,
): Fir2IrResult {
    return Fir2IrConverter.createIrModuleFragment(
        firOutput.session, firOutput.scopeSession, firOutput.fir,
        fir2IrExtensions, fir2IrConfiguration,
        irMangler, IrFactoryImpl, visibilityConverter,
        Fir2IrJvmSpecialAnnotationSymbolProvider(IrFactoryImpl), // TODO KT-60526: replace with appropriate (probably empty) implementation for other backends.
        kotlinBuiltIns = kotlinBuiltIns,
        commonMemberStorage = commonMemberStorage,
        initializedIrBuiltIns = irBuiltIns,
        typeContextProvider = typeContextProvider
    )
}

fun IrPluginContext.applyIrGenerationExtensions(irModuleFragment: IrModuleFragment, irGenerationExtensions: Collection) {
    if (irGenerationExtensions.isEmpty()) return
    for (extension in irGenerationExtensions) {
        extension.generate(irModuleFragment, this)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy