diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/Condition.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/Condition.kt index 4f95cdbd803..84fc13c5ca9 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/Condition.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/Condition.kt @@ -5,69 +5,22 @@ package org.jetbrains.kotlin.fir.resolve.dfa -enum class ConditionValue(val token: String) { - True("true"), False("false"), Null("null"); +enum class Condition { + EqTrue, EqFalse, EqNull, NotEqNull; - override fun toString(): String { - return token + fun invert(): Condition = when (this) { + EqTrue -> EqFalse + EqFalse -> EqTrue + EqNull -> NotEqNull + NotEqNull -> EqNull } - fun invert(): ConditionValue? = when (this) { - True -> False - False -> True - else -> null + override fun toString(): String = when (this) { + EqTrue -> "== True" + EqFalse -> "== False" + EqNull -> "== Null" + NotEqNull -> "!= Null" } } -fun Boolean.toConditionValue(): ConditionValue = if (this) ConditionValue.True else ConditionValue.False - -enum class ConditionOperator(val token: String) { - Eq("=="), NotEq("!="); - - fun invert(): ConditionOperator = when (this) { - Eq -> NotEq - NotEq -> Eq - } - - override fun toString(): String { - return token - } -} - -class Condition(val variable: DataFlowVariable, val rhs: ConditionRHS) { - val operator: ConditionOperator get() = rhs.operator - val value: ConditionValue get() = rhs.value - - constructor( - variable: DataFlowVariable, - operator: ConditionOperator, - value: ConditionValue - ) : this(variable, ConditionRHS(operator, value)) - - override fun toString(): String { - return "$variable $rhs" - } -} - -data class ConditionRHS(val operator: ConditionOperator, val value: ConditionValue) { - fun invert(): ConditionRHS { - val newValue = value.invert() - return if (newValue != null) { - ConditionRHS(operator, newValue) - } else { - ConditionRHS(operator.invert(), value) - } - } - - override fun toString(): String { - return "$operator $value" - } -} - - -internal fun eq(value: ConditionValue): ConditionRHS = ConditionRHS(ConditionOperator.Eq, value) -internal fun notEq(value: ConditionValue): ConditionRHS = ConditionRHS(ConditionOperator.NotEq, value) -internal infix fun DataFlowVariable.eq(value: ConditionValue): Condition = - Condition(this, org.jetbrains.kotlin.fir.resolve.dfa.eq(value)) -internal infix fun DataFlowVariable.notEq(value: ConditionValue): Condition = - Condition(this, org.jetbrains.kotlin.fir.resolve.dfa.notEq(value)) \ No newline at end of file +fun Boolean.toEqBoolean(): Condition = if (this) Condition.EqTrue else Condition.EqFalse \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/DataFlowInferenceContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/DataFlowInferenceContext.kt index 4a721352944..ad112641fa8 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/DataFlowInferenceContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/DataFlowInferenceContext.kt @@ -26,7 +26,7 @@ interface DataFlowInferenceContext : TypeSystemCommonSuperTypesContext, ConeInfe return when (types.size) { 0 -> null 1 -> types.first() - else -> ConeTypeIntersector.intersectTypes(this, types) + else -> ConeTypeIntersector.intersectTypes(this as ConeInferenceContext, types) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzerImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzerImpl.kt index 64c2fa647c4..7678fb57225 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzerImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzerImpl.kt @@ -12,7 +12,7 @@ import org.jetbrains.kotlin.fir.declarations.FirFunction import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents -import org.jetbrains.kotlin.fir.resolve.dfa.ConditionValue.* +import org.jetbrains.kotlin.fir.resolve.dfa.Condition.* import org.jetbrains.kotlin.fir.resolve.dfa.cfg.* import org.jetbrains.kotlin.fir.resolve.transformers.FirBodyResolveTransformer import org.jetbrains.kotlin.fir.symbols.CallableId @@ -87,7 +87,7 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF val previousNode = node.usefulPreviousNodes.singleOrNull() as? WhenBranchConditionExitNode if (previousNode != null) { - node.flow = logicSystem.approveFactsInsideFlow(previousNode.trueCondition, node.flow) + node.flow = logicSystem.approveFactsInsideFlow(previousNode.variable, EqTrue, node.flow) } node.flow.freeze() } @@ -127,14 +127,14 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF flow = flow.addNotApprovedFact( expressionVariable, UnapprovedFirDataFlowInfo( - eq(True), varVariable, chooseInfo(true) + EqTrue, varVariable, chooseInfo(true) ) ) flow = flow.addNotApprovedFact( expressionVariable, UnapprovedFirDataFlowInfo( - eq(False), varVariable, chooseInfo(false) + EqFalse, varVariable, chooseInfo(false) ) ) } @@ -148,12 +148,12 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF flow = flow.addNotApprovedFact( expressionVariable, UnapprovedFirDataFlowInfo( - notEq(Null), varVariable, FirDataFlowInfo(setOf(type), emptySet()) + NotEqNull, varVariable, FirDataFlowInfo(setOf(type), emptySet()) ) ).addNotApprovedFact( expressionVariable, UnapprovedFirDataFlowInfo( - eq(Null), varVariable, FirDataFlowInfo(emptySet(), setOf(type)) + EqNull, varVariable, FirDataFlowInfo(emptySet(), setOf(type)) ) ) } @@ -208,7 +208,7 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF operandVariables.forEach { operandVariable -> flow = flow.addNotApprovedFact( expressionVariable, UnapprovedFirDataFlowInfo( - eq(isEq.toConditionValue()), + isEq.toEqBoolean(), operandVariable, FirDataFlowInfo(setOf(session.builtinTypes.anyType.coneTypeUnsafe()), emptySet()) ) @@ -247,22 +247,22 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF val expressionVariable = getVariable(node.fir) variableStorage[operand]?.let { operandVariable -> - val operator = when (operation) { - FirOperation.EQ, FirOperation.IDENTITY -> ConditionOperator.Eq - FirOperation.NOT_EQ, FirOperation.NOT_IDENTITY -> ConditionOperator.NotEq + val condition = when (operation) { + FirOperation.EQ, FirOperation.IDENTITY -> EqNull + FirOperation.NOT_EQ, FirOperation.NOT_IDENTITY -> NotEqNull else -> throw IllegalArgumentException() } - val facts = logicSystem.approveFact(Condition(operandVariable, operator, Null), flow) + val facts = logicSystem.approveFact(operandVariable, condition, flow) facts.forEach { (variable, info) -> flow = flow.addNotApprovedFact( expressionVariable, UnapprovedFirDataFlowInfo( - eq(True), variable, info + EqTrue, variable, info ) ).addNotApprovedFact( expressionVariable, UnapprovedFirDataFlowInfo( - eq(False), variable, info.invert() + EqFalse, variable, info.invert() ) ) } @@ -272,16 +272,16 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF val operandVariables = getRealVariablesForSafeCallChain(operand).takeIf { it.isNotEmpty() } ?: return - val conditionValue = when (operation) { - FirOperation.EQ, FirOperation.IDENTITY -> False - FirOperation.NOT_EQ, FirOperation.NOT_IDENTITY -> True + val condition = when (operation) { + FirOperation.EQ, FirOperation.IDENTITY -> EqFalse + FirOperation.NOT_EQ, FirOperation.NOT_IDENTITY -> EqTrue else -> throw IllegalArgumentException() } operandVariables.forEach { operandVariable -> flow = flow.addNotApprovedFact( expressionVariable, UnapprovedFirDataFlowInfo( - eq(conditionValue), + condition, operandVariable, FirDataFlowInfo(setOf(session.builtinTypes.anyType.coneTypeUnsafe()), emptySet()) ) @@ -317,7 +317,7 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF val node = graphBuilder.enterWhenBranchCondition(whenBranch).passFlow(false) val previousNode = node.previousNodes.single() if (previousNode is WhenBranchConditionExitNode) { - node.flow = logicSystem.approveFactsInsideFlow(previousNode.falseCondition, node.flow) + node.flow = logicSystem.approveFactsInsideFlow(previousNode.variable, EqFalse, node.flow) } node.flow.freeze() } @@ -326,8 +326,7 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF val node = graphBuilder.exitWhenBranchCondition(whenBranch).passFlow() val conditionVariable = getVariable(whenBranch.condition) - node.trueCondition = conditionVariable eq True - node.falseCondition = conditionVariable eq False + node.variable = conditionVariable } override fun exitWhenBranchResult(whenBranch: FirWhenBranch) { @@ -495,7 +494,7 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF leftNode.passFlow() rightNode.passFlow(false) val leftOperandVariable = getVariable(leftNode.previousNodes.first().fir) - rightNode.flow = logicSystem.approveFactsInsideFlow(leftOperandVariable eq True, rightNode.flow).also { it.freeze() } + rightNode.flow = logicSystem.approveFactsInsideFlow(leftOperandVariable, EqTrue, rightNode.flow).also { it.freeze() } } override fun exitBinaryAnd(binaryLogicExpression: FirBinaryLogicExpression) { @@ -508,10 +507,10 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF val andVariable = getVariable(binaryLogicExpression) - val leftIsTrue = approveFact(leftVariable, True, flowFromRight) - val leftIsFalse = approveFact(leftVariable, False, flowFromRight) - val rightIsTrue = approveFact(rightVariable, True, flowFromRight) ?: mutableMapOf() - val rightIsFalse = approveFact(rightVariable, False, flowFromRight) + val leftIsTrue = approveFact(leftVariable, EqTrue, flowFromRight) + val leftIsFalse = approveFact(leftVariable, EqFalse, flowFromRight) + val rightIsTrue = approveFact(rightVariable, EqTrue, flowFromRight) ?: mutableMapOf() + val rightIsFalse = approveFact(rightVariable, EqFalse, flowFromRight) flowFromRight.approvedFacts.forEach { (variable, info) -> val actualInfo = flowFromLeft.approvedFacts[variable]?.let { info - it } ?: info @@ -520,12 +519,12 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF logicSystem.andForVerifiedFacts(leftIsTrue, rightIsTrue)?.let { for ((variable, info) in it) { - flow.addNotApprovedFact(andVariable, UnapprovedFirDataFlowInfo(eq(True), variable, info)) + flow.addNotApprovedFact(andVariable, UnapprovedFirDataFlowInfo(EqTrue, variable, info)) } } logicSystem.orForVerifiedFacts(leftIsFalse, rightIsFalse)?.let { for ((variable, info) in it) { - flow.addNotApprovedFact(andVariable, UnapprovedFirDataFlowInfo(eq(False), variable, info)) + flow.addNotApprovedFact(andVariable, UnapprovedFirDataFlowInfo(EqFalse, variable, info)) } } node.flow = flow.removeSyntheticVariable(leftVariable).removeSyntheticVariable(rightVariable).also { it.freeze() } @@ -540,7 +539,7 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF leftNode.passFlow() rightNode.passFlow(false) val leftOperandVariable = getVariable(leftNode.previousNodes.first().fir) - rightNode.flow = logicSystem.approveFactsInsideFlow(leftOperandVariable eq False, rightNode.flow).also { it.freeze() } + rightNode.flow = logicSystem.approveFactsInsideFlow(leftOperandVariable, EqFalse, rightNode.flow).also { it.freeze() } } override fun exitBinaryOr(binaryLogicExpression: FirBinaryLogicExpression) { @@ -553,19 +552,19 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF val orVariable = getVariable(binaryLogicExpression) - val leftIsTrue = approveFact(leftVariable, True, flowFromLeft) - val leftIsFalse = approveFact(leftVariable, False, flowFromLeft) - val rightIsTrue = approveFact(rightVariable, True, flowFromRight) - val rightIsFalse = approveFact(rightVariable, False, flowFromRight) + val leftIsTrue = approveFact(leftVariable, EqTrue, flowFromLeft) + val leftIsFalse = approveFact(leftVariable, EqFalse, flowFromLeft) + val rightIsTrue = approveFact(rightVariable, EqTrue, flowFromRight) + val rightIsFalse = approveFact(rightVariable, EqFalse, flowFromRight) logicSystem.orForVerifiedFacts(leftIsTrue, rightIsTrue)?.let { for ((variable, info) in it) { - flow.addNotApprovedFact(orVariable, UnapprovedFirDataFlowInfo(eq(True), variable, info)) + flow.addNotApprovedFact(orVariable, UnapprovedFirDataFlowInfo(EqTrue, variable, info)) } } logicSystem.andForVerifiedFacts(leftIsFalse, rightIsFalse)?.let { for ((variable, info) in it) { - flow.addNotApprovedFact(orVariable, UnapprovedFirDataFlowInfo(eq(False), variable, info)) + flow.addNotApprovedFact(orVariable, UnapprovedFirDataFlowInfo(EqFalse, variable, info)) } } node.flow = flow.removeSyntheticVariable(leftVariable).removeSyntheticVariable(rightVariable).also { it.freeze() } @@ -599,8 +598,8 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF // ------------------------------------------------------------------------------------------------------------------------- - private fun approveFact(variable: DataFlowVariable, value: ConditionValue, flow: Flow): MutableMap? = - logicSystem.approveFact(variable eq value, flow) + private fun approveFact(variable: DataFlowVariable, condition: Condition, flow: Flow): MutableMap? = + logicSystem.approveFact(variable, condition, flow) private fun FirBinaryLogicExpression.getVariables(): Pair = getVariable(leftOperand) to getVariable(rightOperand) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowInfo.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowInfo.kt index a33a8f2bd87..d777e8ca74c 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowInfo.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowInfo.kt @@ -9,7 +9,7 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.render data class UnapprovedFirDataFlowInfo( - val condition: ConditionRHS, + val condition: Condition, val variable: DataFlowVariable, val info: FirDataFlowInfo ) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt index 2e0a5fc2199..85d7f11415e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt @@ -69,8 +69,8 @@ class LogicSystem(private val context: DataFlowInferenceContext) { return map } - fun approveFactsInsideFlow(proof: Condition, flow: Flow): Flow { - val notApprovedFacts: Set = flow.notApprovedFacts[proof.variable] + fun approveFactsInsideFlow(variable: DataFlowVariable, condition: Condition, flow: Flow): Flow { + val notApprovedFacts: Set = flow.notApprovedFacts[variable] if (notApprovedFacts.isEmpty()) { return flow } @@ -78,7 +78,7 @@ class LogicSystem(private val context: DataFlowInferenceContext) { val flow = flow.copyForBuilding() val newFacts = HashMultimap.create() notApprovedFacts.forEach { - if (it.condition == proof.rhs) { + if (it.condition == condition) { newFacts.put(it.variable, it.info) } } @@ -93,14 +93,14 @@ class LogicSystem(private val context: DataFlowInferenceContext) { return flow } - fun approveFact(proof: Condition, flow: Flow): MutableMap { - val notApprovedFacts: Set = flow.notApprovedFacts[proof.variable] + fun approveFact(variable: DataFlowVariable, condition: Condition, flow: Flow): MutableMap { + val notApprovedFacts: Set = flow.notApprovedFacts[variable] if (notApprovedFacts.isEmpty()) { return mutableMapOf() } val newFacts = HashMultimap.create() notApprovedFacts.forEach { - if (it.condition == proof.rhs) { + if (it.condition == condition) { newFacts.put(it.variable, it.info) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt index c9d0d2384a8..6f4e266acfd 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraph.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.fir.declarations.FirAnonymousInitializer import org.jetbrains.kotlin.fir.declarations.FirFunction import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.expressions.* -import org.jetbrains.kotlin.fir.resolve.dfa.Condition +import org.jetbrains.kotlin.fir.resolve.dfa.DataFlowVariable class ControlFlowGraph(val name: String) { val nodes = mutableListOf>() @@ -67,8 +67,7 @@ class WhenEnterNode(owner: ControlFlowGraph, override val fir: FirWhenExpression class WhenExitNode(owner: ControlFlowGraph, override val fir: FirWhenExpression, level: Int) : CFGNode(owner, level), ExitNode class WhenBranchConditionEnterNode(owner: ControlFlowGraph, override val fir: FirWhenBranch, level: Int) : CFGNode(owner, level), EnterNode class WhenBranchConditionExitNode(owner: ControlFlowGraph, override val fir: FirWhenBranch, level: Int) : CFGNode(owner, level), ExitNode { - lateinit var trueCondition: Condition - lateinit var falseCondition: Condition + lateinit var variable: DataFlowVariable } class WhenBranchResultExitNode(owner: ControlFlowGraph, override val fir: FirWhenBranch, level: Int) : CFGNode(owner, level)