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

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2020 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 org.jetbrains.kotlin.fir.types.ConeInferenceContext
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.commonSuperTypeOrNull

abstract class Flow {
    abstract fun getTypeStatement(variable: RealVariable): TypeStatement?
    abstract fun getImplications(variable: DataFlowVariable): Collection
    abstract fun getVariablesInTypeStatements(): Collection
    abstract fun removeOperations(variable: DataFlowVariable): Collection

    abstract val directAliasMap: Map
    abstract val backwardsAliasMap: Map>
}

fun Flow.unwrapVariable(variable: RealVariable): RealVariable {
    return directAliasMap[variable]?.variable ?: variable
}

abstract class LogicSystem(protected val context: ConeInferenceContext) {
    // ------------------------------- Flow operations -------------------------------

    abstract fun createEmptyFlow(): FLOW
    abstract fun forkFlow(flow: FLOW): FLOW
    abstract fun joinFlow(flows: Collection): FLOW
    abstract fun unionFlow(flows: Collection): FLOW

    abstract fun addTypeStatement(flow: FLOW, statement: TypeStatement)

    abstract fun addImplication(flow: FLOW, implication: Implication)

    abstract fun removeAllAboutVariable(flow: FLOW, variable: RealVariable)

    abstract fun translateVariableFromConditionInStatements(
        flow: FLOW,
        originalVariable: DataFlowVariable,
        newVariable: DataFlowVariable,
        shouldRemoveOriginalStatements: Boolean,
        filter: (Implication) -> Boolean = { true },
        transform: (Implication) -> Implication = { it },
    )

    abstract fun approveStatementsInsideFlow(
        flow: FLOW,
        approvedStatement: OperationStatement,
        shouldForkFlow: Boolean,
        shouldRemoveSynthetics: Boolean,
    ): FLOW

    abstract fun addLocalVariableAlias(flow: FLOW, alias: RealVariable, underlyingVariable: RealVariableAndType)
    abstract fun removeLocalVariableAlias(flow: FLOW, alias: RealVariable)

    protected abstract fun getImplicationsWithVariable(flow: FLOW, variable: DataFlowVariable): Collection

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

    abstract fun processUpdatedReceiverVariable(flow: FLOW, variable: RealVariable)
    abstract fun updateAllReceivers(flow: FLOW)

    // ------------------------------- Public TypeStatement util functions -------------------------------

    data class InfoForBooleanOperator(
        val conditionalFromLeft: Collection,
        val conditionalFromRight: Collection,
        val knownFromRight: TypeStatements,
    )

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

    abstract fun approveStatementsTo(
        destination: MutableTypeStatements,
        flow: FLOW,
        approvedStatement: OperationStatement,
        statements: Collection,
    )

    /**
     * Recursively collects all TypeStatements approved by [approvedStatement] and all predicates
     *   that has been implied by it
     *   TODO: or not recursively?
     */
    fun approveOperationStatement(flow: FLOW, approvedStatement: OperationStatement): Collection {
        val statements = getImplicationsWithVariable(flow, approvedStatement.variable)
        return approveOperationStatement(flow, approvedStatement, statements).values
    }

    fun orForTypeStatements(
        left: TypeStatements,
        right: TypeStatements,
    ): MutableTypeStatements {
        if (left.isNullOrEmpty() || right.isNullOrEmpty()) return mutableMapOf()
        val map = mutableMapOf()
        for (variable in left.keys.intersect(right.keys)) {
            val leftStatement = left.getValue(variable)
            val rightStatement = right.getValue(variable)
            map[variable] = or(listOf(leftStatement, rightStatement))
        }
        return map
    }

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

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

    protected fun or(statements: Collection): MutableTypeStatement {
        require(statements.isNotEmpty())
        statements.singleOrNull()?.let { return it as MutableTypeStatement }
        val variable = statements.first().variable
        assert(statements.all { it.variable == variable })
        val exactType = orForTypes(statements.map { it.exactType })
        val exactNotType = orForTypes(statements.map { it.exactNotType })
        return MutableTypeStatement(variable, exactType, exactNotType)
    }

    private fun orForTypes(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 = types.mapNotNull { typeSet -> (typeSet - commonTypes).takeIf { it.isNotEmpty() } }
        if (differentTypes.size == types.size) {
            context.commonSuperTypeOrNull(differentTypes.flatten())?.let { commonTypes += it }
        }
        return commonTypes
    }

    protected fun and(statements: Collection): MutableTypeStatement {
        require(statements.isNotEmpty())
        statements.singleOrNull()?.let { return it as MutableTypeStatement }
        val variable = statements.first().variable
        assert(statements.all { it.variable == variable })
        val exactType = andForTypes(statements.map { it.exactType })
        val exactNotType = andForTypes(statements.map { it.exactNotType })
        return MutableTypeStatement(variable, exactType, exactNotType)
    }

    private fun andForTypes(types: Collection>): MutableSet {
        return types.flatMapTo(mutableSetOf()) { it }
    }
}

fun  LogicSystem.approveOperationStatement(
    flow: FLOW,
    approvedStatement: OperationStatement,
    statements: Collection,
): MutableTypeStatements {
    return mutableMapOf().apply {
        approveStatementsTo(this, flow, approvedStatement, statements)
    }
}

/*
 *  used for:
 *   1. val b = x is String
 *   2. b = x is String
 *   3. !b | b.not()   for Booleans
 */
fun  LogicSystem.replaceVariableFromConditionInStatements(
    flow: F,
    originalVariable: DataFlowVariable,
    newVariable: DataFlowVariable,
    filter: (Implication) -> Boolean = { true },
    transform: (Implication) -> Implication = { it },
) {
    translateVariableFromConditionInStatements(
        flow,
        originalVariable,
        newVariable,
        shouldRemoveOriginalStatements = true,
        filter,
        transform,
    )
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy