[FIR] Refactor Condition classes
This commit is contained in:
@@ -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))
|
||||
fun Boolean.toEqBoolean(): Condition = if (this) Condition.EqTrue else Condition.EqFalse
|
||||
+1
-1
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+35
-36
@@ -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<DataFlowVariable, FirDataFlowInfo>? =
|
||||
logicSystem.approveFact(variable eq value, flow)
|
||||
private fun approveFact(variable: DataFlowVariable, condition: Condition, flow: Flow): MutableMap<DataFlowVariable, FirDataFlowInfo>? =
|
||||
logicSystem.approveFact(variable, condition, flow)
|
||||
|
||||
private fun FirBinaryLogicExpression.getVariables(): Pair<DataFlowVariable, DataFlowVariable> =
|
||||
getVariable(leftOperand) to getVariable(rightOperand)
|
||||
|
||||
@@ -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
|
||||
) {
|
||||
|
||||
@@ -69,8 +69,8 @@ class LogicSystem(private val context: DataFlowInferenceContext) {
|
||||
return map
|
||||
}
|
||||
|
||||
fun approveFactsInsideFlow(proof: Condition, flow: Flow): Flow {
|
||||
val notApprovedFacts: Set<UnapprovedFirDataFlowInfo> = flow.notApprovedFacts[proof.variable]
|
||||
fun approveFactsInsideFlow(variable: DataFlowVariable, condition: Condition, flow: Flow): Flow {
|
||||
val notApprovedFacts: Set<UnapprovedFirDataFlowInfo> = 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<DataFlowVariable, FirDataFlowInfo>()
|
||||
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<DataFlowVariable, FirDataFlowInfo> {
|
||||
val notApprovedFacts: Set<UnapprovedFirDataFlowInfo> = flow.notApprovedFacts[proof.variable]
|
||||
fun approveFact(variable: DataFlowVariable, condition: Condition, flow: Flow): MutableMap<DataFlowVariable, FirDataFlowInfo> {
|
||||
val notApprovedFacts: Set<UnapprovedFirDataFlowInfo> = flow.notApprovedFacts[variable]
|
||||
if (notApprovedFacts.isEmpty()) {
|
||||
return mutableMapOf()
|
||||
}
|
||||
val newFacts = HashMultimap.create<DataFlowVariable, FirDataFlowInfo>()
|
||||
notApprovedFacts.forEach {
|
||||
if (it.condition == proof.rhs) {
|
||||
if (it.condition == condition) {
|
||||
newFacts.put(it.variable, it.info)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -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<CFGNode<*>>()
|
||||
@@ -67,8 +67,7 @@ class WhenEnterNode(owner: ControlFlowGraph, override val fir: FirWhenExpression
|
||||
class WhenExitNode(owner: ControlFlowGraph, override val fir: FirWhenExpression, level: Int) : CFGNode<FirWhenExpression>(owner, level), ExitNode
|
||||
class WhenBranchConditionEnterNode(owner: ControlFlowGraph, override val fir: FirWhenBranch, level: Int) : CFGNode<FirWhenBranch>(owner, level), EnterNode
|
||||
class WhenBranchConditionExitNode(owner: ControlFlowGraph, override val fir: FirWhenBranch, level: Int) : CFGNode<FirWhenBranch>(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<FirWhenBranch>(owner, level)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user