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

org.jetbrains.kotlin.backend.common.actualizer.IrActualizer.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-RC
Show newest version
/*
 * 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.KtDiagnosticReporterWithImplicitIrBasedContext
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
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

data class IrActualizedResult(val actualizedExpectDeclarations: List)

object IrActualizer {
    fun actualize(
        mainFragment: IrModuleFragment,
        dependentFragments: List,
        diagnosticReporter: DiagnosticReporter,
        typeSystemContext: IrTypeSystemContext,
        languageVersionSettings: LanguageVersionSettings,
        expectActualTracker: ExpectActualTracker?
    ): IrActualizedResult {
        val ktDiagnosticReporter = KtDiagnosticReporterWithImplicitIrBasedContext(diagnosticReporter, languageVersionSettings)

        // 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()
        if (languageVersionSettings.supportsFeature(LanguageFeature.MultiplatformRestrictions)) {
            IrExpectActualAnnotationMatchingChecker(expectActualMap, actualDeclarations, typeSystemContext, ktDiagnosticReporter).check()
        }

        //   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)

        //   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) } }

        //   5. Copy and actualize function parameter default values from expect functions
        val symbolRemapper = ActualizerSymbolRemapper(expectActualMap)
        val typeRemapper = DeepCopyTypeRemapper(symbolRemapper)
        FunctionDefaultParametersActualizer(symbolRemapper, typeRemapper, expectActualMap).actualize()

        //   6. Actualize expect calls in dependent fragments using info obtained in the previous steps
        val actualizerVisitor = ActualizerVisitor(symbolRemapper, typeRemapper)
        dependentFragments.forEach { it.transform(actualizerVisitor, null) }

        //   7. Merge dependent fragments into the main one
        mergeIrFragments(mainFragment, dependentFragments)

        return IrActualizedResult(removedExpectDeclarations)
    }

    private fun removeExpectDeclarations(dependentFragments: List, expectActualMap: Map): List {
        val removedExpectDeclarations = mutableListOf()
        for (fragment in dependentFragments) {
            for (file in fragment.files) {
                file.declarations.removeIf {
                    if (shouldRemoveExpectDeclaration(it, expectActualMap)) {
                        removedExpectDeclarations.add(it)
                        true
                    } else {
                        false
                    }
                }
            }
        }
        return removedExpectDeclarations
    }

    private fun shouldRemoveExpectDeclaration(irDeclaration: IrDeclaration, expectActualMap: Map): Boolean {
        return when (irDeclaration) {
            is IrClass -> irDeclaration.isExpect && (!irDeclaration.containsOptionalExpectation() || expectActualMap.containsKey(irDeclaration.symbol))
            is IrProperty -> irDeclaration.isExpect
            is IrFunction -> irDeclaration.isExpect
            else -> false
        }
    }

    private fun mergeIrFragments(mainFragment: IrModuleFragment, dependentFragments: List) {
        mainFragment.files.addAll(0, dependentFragments.flatMap { it.files })
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy