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

org.jetbrains.kotlin.backend.common.actualizer.SpecialFakeOverrideSymbolsResolver.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.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.ir.visitors.acceptVoid

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

    fun cacheFakeOverridesOfAllClasses(irModuleFragment: IrModuleFragment) {
        val visitor = object : IrElementVisitorVoid {
            override fun visitElement(element: IrElement) {}

            override fun visitFile(declaration: IrFile) {
                declaration.acceptChildrenVoid(this)
            }

            override fun visitClass(declaration: IrClass) {
                if (!declaration.isExpect) {
                    processClass(declaration)
                }
                declaration.acceptChildrenVoid(this)
            }
        }
        irModuleFragment.acceptChildrenVoid(visitor)
    }
}


class SpecialFakeOverrideSymbolsResolverVisitor(private val resolver: SpecialFakeOverrideSymbolsResolver) : IrElementVisitorVoid {
    override fun visitElement(element: IrElement) {
        // E.g. annotation can contain fake override of constant property
        if (element is IrAnnotationContainer) {
            for (annotation in element.annotations) {
                annotation.acceptVoid(this)
            }
        }
        element.acceptChildrenVoid(this)
    }

    override fun visitSimpleFunction(declaration: IrSimpleFunction) {
        declaration.overriddenSymbols = declaration.overriddenSymbols.map(resolver::getReferencedSimpleFunction)
        visitElement(declaration)
    }

    override fun visitProperty(declaration: IrProperty) {
        declaration.overriddenSymbols = declaration.overriddenSymbols.map(resolver::getReferencedProperty)
        visitElement(declaration)
    }

    override fun visitCall(expression: IrCall) {
        expression.symbol = resolver.getReferencedSimpleFunction(expression.symbol)
        visitElement(expression)
    }

    override fun visitFunctionReference(expression: IrFunctionReference) {
        expression.symbol = resolver.getReferencedFunction(expression.symbol)
        expression.reflectionTarget = expression.reflectionTarget?.let(resolver::getReferencedFunction)
        visitElement(expression)
    }

    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)
        visitElement(expression)
    }

    override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference) {
        expression.getter = expression.getter.let(resolver::getReferencedSimpleFunction)
        expression.setter = expression.setter?.let(resolver::getReferencedSimpleFunction)
        visitElement(expression)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy