[FIR] Refactor Condition classes

This commit is contained in:
Dmitriy Novozhilov
2019-08-30 12:17:40 +03:00
parent 84787013dd
commit 92acd30bd6
6 changed files with 58 additions and 107 deletions
@@ -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
@@ -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)
}
}
@@ -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)
}
}
@@ -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)