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

org.jetbrains.kotlin.fir.resolve.dfa.LogicSystem.kt Maven / Gradle / Ivy

/*
 * Copyright 2010-2019 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.resolve.dfa

import com.google.common.collect.ArrayListMultimap
import org.jetbrains.kotlin.fir.types.ConeKotlinType

interface Flow {
    fun getApprovedInfo(variable: RealDataFlowVariable): FirDataFlowInfo?
    fun getConditionalInfos(variable: DataFlowVariable): Collection

    fun getVariablesInApprovedInfos(): Collection

    fun removeConditionalInfos(variable: DataFlowVariable): Collection
}

abstract class LogicSystem(private val context: DataFlowInferenceContext) {

    // ------------------------------- Flow operations -------------------------------

    abstract fun createEmptyFlow(): Flow
    abstract fun forkFlow(flow: Flow): Flow
    abstract fun joinFlow(flows: Collection): Flow

    open fun addApprovedInfo(flow: Flow, variable: RealDataFlowVariable, info: FirDataFlowInfo) {
        assert(info is MutableFirDataFlowInfo)
        flow.approvedInfos.addInfo(variable, info)
        if (variable.isThisReference) {
            processUpdatedReceiverVariable(flow, variable)
        }
    }

    open fun addConditionalInfo(flow: Flow, variable: DataFlowVariable, info: ConditionalFirDataFlowInfo) {
        flow.conditionalInfos.put(variable, info)
    }

    /*
     *  used for:
     *   1. val b = x is String
     *   2. b = x is String
     *   3. !b | b.not()   for Booleans
     */
    open fun changeVariableForConditionFlow(
        flow: Flow,
        sourceVariable: DataFlowVariable,
        newVariable: DataFlowVariable,
        transform: ((ConditionalFirDataFlowInfo) -> ConditionalFirDataFlowInfo)? = null
    ) {
        var infos = flow.getConditionalInfos(sourceVariable)
        if (transform != null) {
            infos = infos.map(transform)
        }
        flow.conditionalInfos.putAll(newVariable, infos)
        if (sourceVariable.isSynthetic()) {
            flow.conditionalInfos.removeAll(sourceVariable)
        }
    }

    open fun approveFactsInsideFlow(
        variable: DataFlowVariable,
        condition: Condition,
        flow: Flow,
        shouldForkFlow: Boolean,
        shouldRemoveSynthetics: Boolean
    ): Flow {
        val notApprovedFacts: Collection = if (shouldRemoveSynthetics && variable.isSynthetic()) {
            flow.removeConditionalInfos(variable)
        } else {
            flow.getConditionalInfos(variable)
        }

        val resultFlow = if (shouldForkFlow) forkFlow(flow) else flow
        if (notApprovedFacts.isEmpty()) {
            return resultFlow
        }

        val newFacts = ArrayListMultimap.create()
        notApprovedFacts.forEach {
            if (it.condition == condition) {
                newFacts.put(it.variable, it.info)
            }
        }

        val updatedReceivers = mutableSetOf()

        newFacts.asMap().forEach { (variable, infos) ->
            @Suppress("NAME_SHADOWING")
            val info = MutableFirDataFlowInfo()
            infos.forEach {
                info += it
            }
            if (variable.isThisReference) {
                updatedReceivers += variable
            }
            addApprovedInfo(resultFlow, variable, info)
        }
        updatedReceivers.forEach {
            processUpdatedReceiverVariable(resultFlow, it)
        }
        return resultFlow
    }

    // ------------------------------- Callbacks for updating implicit receiver stack -------------------------------

    abstract fun processUpdatedReceiverVariable(flow: Flow, variable: RealDataFlowVariable)
    abstract fun updateAllReceivers(flow: Flow)

    // ------------------------------- Accessors to flow implementation -------------------------------

    protected abstract val Flow.approvedInfos: MutableApprovedInfos
    protected abstract val Flow.conditionalInfos: ConditionalInfos

    // ------------------------------- Public DataFlowInfo util functions -------------------------------

    data class InfoForBooleanOperator(
        val conditionalFromLeft: Collection,
        val conditionalFromRight: Collection,
        val approvedFromRight: ApprovedInfos
    )

    abstract fun collectInfoForBooleanOperator(
        leftFlow: Flow,
        leftVariable: DataFlowVariable,
        rightFlow: Flow,
        rightVariable: DataFlowVariable
    ): InfoForBooleanOperator

    fun orForVerifiedFacts(
        left: ApprovedInfos,
        right: ApprovedInfos
    ): MutableApprovedInfos {
        if (left.isNullOrEmpty() || right.isNullOrEmpty()) return mutableMapOf()
        val map = mutableMapOf()
        for (variable in left.keys.intersect(right.keys)) {
            val leftInfo = left.getValue(variable)
            val rightInfo = right.getValue(variable)
            map[variable] = or(listOf(leftInfo, rightInfo))
        }
        return map
    }

    fun approveFactTo(destination: MutableApprovedInfos, variable: DataFlowVariable, condition: Condition, flow: Flow) {
        val notApprovedFacts: Collection = flow.getConditionalInfos(variable)
        approveFactTo(destination, condition, notApprovedFacts)
    }

    fun approveFactTo(destination: MutableApprovedInfos, condition: Condition, notApprovedFacts: Collection) {
        if (notApprovedFacts.isEmpty()) return
        notApprovedFacts.forEach {
            if (it.condition == condition) {
                destination.addInfo(it.variable, it.info)
            }
        }
    }

    fun approveFact(condition: Condition, notApprovedFacts: Collection): MutableApprovedInfos {
        return mutableMapOf().apply { approveFactTo(this, condition, notApprovedFacts) }
    }

    fun approveFact(variable: DataFlowVariable, condition: Condition, flow: Flow): MutableApprovedInfos {
        return mutableMapOf().apply { approveFactTo(this, variable, condition, flow) }
    }

    // ------------------------------- Util functions -------------------------------

    // TODO
    protected fun  Collection>.intersectSets(): Set {
        if (isEmpty()) return emptySet()
        val iterator = iterator()
        val result = HashSet(iterator.next())
        while (iterator.hasNext()) {
            result.retainAll(iterator.next())
        }
        return result
    }

    protected fun or(infos: Collection): MutableFirDataFlowInfo {
        infos.singleOrNull()?.let { return it as MutableFirDataFlowInfo }
        val exactType = orTypes(infos.map { it.exactType })
        val exactNotType = orTypes(infos.map { it.exactNotType })
        return MutableFirDataFlowInfo(exactType, exactNotType)
    }

    private fun orTypes(types: Collection>): MutableSet {
        if (types.any { it.isEmpty() }) return mutableSetOf()
        val allTypes = types.flatMapTo(mutableSetOf()) { it }
        val commonTypes = allTypes.toMutableSet()
        types.forEach { commonTypes.retainAll(it) }
        val differentTypes = allTypes - commonTypes
        context.commonSuperTypeOrNull(differentTypes.toList())?.let { commonTypes += it }
        return commonTypes
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy