diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt index 976265e9742..147afc015e1 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt @@ -139,7 +139,7 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() { statement: OperationStatement, builtinTypes: BuiltinTypes ): TypeStatements { - val newTypeStatements = andForTypeStatements(flow.approvedTypeStatements, approveOperationStatement(flow, statement, null)) + val newTypeStatements = andForTypeStatements(flow.approvedTypeStatements, approveOperationStatement(flow, statement)) val variable = statement.variable if (!variable.isReal()) return newTypeStatements val extraStatement = when (statement.operation) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt index 6ae02fdded0..0623afd73fa 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt @@ -1176,15 +1176,12 @@ abstract class FirDataFlowAnalyzer( // has to be `onlyLeftEvaluated`, and it has to be produced by the left operand. logicSystem.commitOperationStatement(flow, leftVariable eq onlyLeftEvaluated, shouldRemoveSynthetics = true) } else { - val (conditionalFromLeft, conditionalFromRight, approvedFromRight) = - logicSystem.collectInfoForBooleanOperator(flowFromLeft, leftVariable, flowFromRight, rightVariable) - // If `left && right` is true, then both are true (and evaluated). // If `left || right` is false, then both are false. arrayOf( - approvedFromRight, - logicSystem.approveOperationStatement(flowFromRight, leftVariable eq bothEvaluated, conditionalFromLeft), - logicSystem.approveOperationStatement(flowFromRight, rightVariable eq bothEvaluated, conditionalFromRight), + flowFromRight.approvedTypeStatements, + // `leftVariable eq bothEvaluated` already approved in flowFromRight. + logicSystem.approveOperationStatement(flowFromRight, rightVariable eq bothEvaluated), ).forEach { statements -> statements.values.forEach { flow.addImplication((operatorVariable eq bothEvaluated) implies it) } } @@ -1192,10 +1189,10 @@ abstract class FirDataFlowAnalyzer( // If `left && right` is false, then either `left` is false, or both were evaluated and `right` is false. // If `left || right` is true, then either `left` is true, or both were evaluated and `right` is true. logicSystem.orForTypeStatements( - logicSystem.approveOperationStatement(flowFromLeft, leftVariable eq onlyLeftEvaluated, conditionalFromLeft), - // TODO: and(approvedFromRight, ...)? FE1.0 doesn't seem to handle that correctly either. + logicSystem.approveOperationStatement(flowFromLeft, leftVariable eq onlyLeftEvaluated), + // TODO: and(approved from right, ...)? FE1.0 doesn't seem to handle that correctly either. // if (x is A || whatever(x as B)) { /* x is (A | B) */ } - logicSystem.approveOperationStatement(flowFromRight, rightVariable eq onlyLeftEvaluated, conditionalFromRight), + logicSystem.approveOperationStatement(flowFromRight, rightVariable eq onlyLeftEvaluated), ).values.forEach { flow.addImplication((operatorVariable eq onlyLeftEvaluated) implies it) } } diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/Flow.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/Flow.kt index 6f1f5d9a66e..5d09bcbf939 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/Flow.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/Flow.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve.dfa import org.jetbrains.kotlin.fir.types.ConeKotlinType abstract class Flow { + abstract val approvedTypeStatements: TypeStatements abstract fun unwrapVariable(variable: RealVariable): RealVariable abstract fun getType(variable: RealVariable): Set? } diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt index 8f08ad09470..b7ed066c5c4 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt @@ -49,24 +49,7 @@ abstract class LogicSystem(protected val context: ConeInferenceCont // ------------------------------- 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 approveOperationStatement( - flow: FLOW, - approvedStatement: OperationStatement, - statementsForVariable: Collection? - ): TypeStatements + abstract fun approveOperationStatement(flow: FLOW, approvedStatement: OperationStatement): TypeStatements fun orForTypeStatements(left: TypeStatements, right: TypeStatements): TypeStatements = when { left.isEmpty() -> left diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/PersistentLogicSystem.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/PersistentLogicSystem.kt index 33df336b727..29eff5959c5 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/PersistentLogicSystem.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/PersistentLogicSystem.kt @@ -23,7 +23,7 @@ typealias PersistentImplications = PersistentMap?, shouldRemoveSynthetics: Boolean ): TypeStatements { val approvedTypeStatements: ArrayListMultimap = ArrayListMultimap.create() val queue = LinkedList().apply { this += approvedStatement } val approved = mutableSetOf() - var firstIteration = true while (queue.isNotEmpty()) { val next: OperationStatement = queue.removeFirst() // Defense from cycles in facts if (!approved.add(next)) continue val variable = next.variable - val statements = initialStatements?.takeIf { firstIteration } - ?: flow.logicStatements[variable]?.takeIf { it.isNotEmpty() } - ?: continue + val statements = flow.logicStatements[variable]?.takeIf { it.isNotEmpty() } ?: continue if (shouldRemoveSynthetics && variable.isSynthetic()) { flow.logicStatements -= variable } @@ -291,7 +287,6 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste } } } - firstIteration = false } return approvedTypeStatements.asMap().mapValues { and(it.value) } } @@ -299,21 +294,7 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste override fun approveOperationStatement( flow: PersistentFlow, approvedStatement: OperationStatement, - statementsForVariable: Collection? - ): TypeStatements = approveOperationStatementsInternal(flow, approvedStatement, statementsForVariable, shouldRemoveSynthetics = false) - - override fun collectInfoForBooleanOperator( - leftFlow: PersistentFlow, - leftVariable: DataFlowVariable, - rightFlow: PersistentFlow, - rightVariable: DataFlowVariable - ): InfoForBooleanOperator { - return InfoForBooleanOperator( - leftFlow.logicStatements[leftVariable] ?: emptyList(), - rightFlow.logicStatements[rightVariable] ?: emptyList(), - rightFlow.approvedTypeStatements - ) - } + ): TypeStatements = approveOperationStatementsInternal(flow, approvedStatement, shouldRemoveSynthetics = false) override fun getImplicationsWithVariable(flow: PersistentFlow, variable: DataFlowVariable): Collection { return flow.logicStatements[variable] ?: emptyList() diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/11.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/11.fir.kt index 5229e0235d5..633738a04a3 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/11.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/11.fir.kt @@ -5,8 +5,8 @@ fun case_1() { var x: Boolean? = true if (x is Boolean && if (true) { x = null; true } else { false }) { - x - x.not() + x + x.not() } } @@ -14,8 +14,8 @@ fun case_1() { fun case_2() { var x: Boolean? = true if (x != null && try { x = null; true } catch (e: Exception) { false }) { - x - x.not() + x + x.not() } } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/15.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/15.fir.kt index 8b7d0c50ebe..a1f60d1333d 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/15.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/15.fir.kt @@ -9,8 +9,8 @@ fun case_1() { var x: Boolean? = true if (x is Boolean && if (true) { x = null; true } else { false }) { - x - x.not() + x + x.not() } } @@ -22,8 +22,8 @@ fun case_1() { fun case_2() { var x: Boolean? = true if (x !== null && try { x = null; true } catch (e: Exception) { false }) { - x - x.not() + x + x.not() } }