[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 package org.jetbrains.kotlin.fir.resolve.dfa
enum class ConditionValue(val token: String) { enum class Condition {
True("true"), False("false"), Null("null"); EqTrue, EqFalse, EqNull, NotEqNull;
override fun toString(): String { fun invert(): Condition = when (this) {
return token EqTrue -> EqFalse
EqFalse -> EqTrue
EqNull -> NotEqNull
NotEqNull -> EqNull
} }
fun invert(): ConditionValue? = when (this) { override fun toString(): String = when (this) {
True -> False EqTrue -> "== True"
False -> True EqFalse -> "== False"
else -> null EqNull -> "== Null"
NotEqNull -> "!= Null"
} }
} }
fun Boolean.toConditionValue(): ConditionValue = if (this) ConditionValue.True else ConditionValue.False fun Boolean.toEqBoolean(): Condition = if (this) Condition.EqTrue else Condition.EqFalse
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))
@@ -26,7 +26,7 @@ interface DataFlowInferenceContext : TypeSystemCommonSuperTypesContext, ConeInfe
return when (types.size) { return when (types.size) {
0 -> null 0 -> null
1 -> types.first() 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.declarations.FirProperty
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents 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.dfa.cfg.*
import org.jetbrains.kotlin.fir.resolve.transformers.FirBodyResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.FirBodyResolveTransformer
import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.CallableId
@@ -87,7 +87,7 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF
val previousNode = node.usefulPreviousNodes.singleOrNull() as? WhenBranchConditionExitNode val previousNode = node.usefulPreviousNodes.singleOrNull() as? WhenBranchConditionExitNode
if (previousNode != null) { if (previousNode != null) {
node.flow = logicSystem.approveFactsInsideFlow(previousNode.trueCondition, node.flow) node.flow = logicSystem.approveFactsInsideFlow(previousNode.variable, EqTrue, node.flow)
} }
node.flow.freeze() node.flow.freeze()
} }
@@ -127,14 +127,14 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF
flow = flow.addNotApprovedFact( flow = flow.addNotApprovedFact(
expressionVariable, expressionVariable,
UnapprovedFirDataFlowInfo( UnapprovedFirDataFlowInfo(
eq(True), varVariable, chooseInfo(true) EqTrue, varVariable, chooseInfo(true)
) )
) )
flow = flow.addNotApprovedFact( flow = flow.addNotApprovedFact(
expressionVariable, expressionVariable,
UnapprovedFirDataFlowInfo( UnapprovedFirDataFlowInfo(
eq(False), varVariable, chooseInfo(false) EqFalse, varVariable, chooseInfo(false)
) )
) )
} }
@@ -148,12 +148,12 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF
flow = flow.addNotApprovedFact( flow = flow.addNotApprovedFact(
expressionVariable, expressionVariable,
UnapprovedFirDataFlowInfo( UnapprovedFirDataFlowInfo(
notEq(Null), varVariable, FirDataFlowInfo(setOf(type), emptySet()) NotEqNull, varVariable, FirDataFlowInfo(setOf(type), emptySet())
) )
).addNotApprovedFact( ).addNotApprovedFact(
expressionVariable, expressionVariable,
UnapprovedFirDataFlowInfo( 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 -> operandVariables.forEach { operandVariable ->
flow = flow.addNotApprovedFact( flow = flow.addNotApprovedFact(
expressionVariable, UnapprovedFirDataFlowInfo( expressionVariable, UnapprovedFirDataFlowInfo(
eq(isEq.toConditionValue()), isEq.toEqBoolean(),
operandVariable, operandVariable,
FirDataFlowInfo(setOf(session.builtinTypes.anyType.coneTypeUnsafe()), emptySet()) FirDataFlowInfo(setOf(session.builtinTypes.anyType.coneTypeUnsafe()), emptySet())
) )
@@ -247,22 +247,22 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF
val expressionVariable = getVariable(node.fir) val expressionVariable = getVariable(node.fir)
variableStorage[operand]?.let { operandVariable -> variableStorage[operand]?.let { operandVariable ->
val operator = when (operation) { val condition = when (operation) {
FirOperation.EQ, FirOperation.IDENTITY -> ConditionOperator.Eq FirOperation.EQ, FirOperation.IDENTITY -> EqNull
FirOperation.NOT_EQ, FirOperation.NOT_IDENTITY -> ConditionOperator.NotEq FirOperation.NOT_EQ, FirOperation.NOT_IDENTITY -> NotEqNull
else -> throw IllegalArgumentException() else -> throw IllegalArgumentException()
} }
val facts = logicSystem.approveFact(Condition(operandVariable, operator, Null), flow) val facts = logicSystem.approveFact(operandVariable, condition, flow)
facts.forEach { (variable, info) -> facts.forEach { (variable, info) ->
flow = flow.addNotApprovedFact( flow = flow.addNotApprovedFact(
expressionVariable, expressionVariable,
UnapprovedFirDataFlowInfo( UnapprovedFirDataFlowInfo(
eq(True), variable, info EqTrue, variable, info
) )
).addNotApprovedFact( ).addNotApprovedFact(
expressionVariable, expressionVariable,
UnapprovedFirDataFlowInfo( 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 operandVariables = getRealVariablesForSafeCallChain(operand).takeIf { it.isNotEmpty() } ?: return
val conditionValue = when (operation) { val condition = when (operation) {
FirOperation.EQ, FirOperation.IDENTITY -> False FirOperation.EQ, FirOperation.IDENTITY -> EqFalse
FirOperation.NOT_EQ, FirOperation.NOT_IDENTITY -> True FirOperation.NOT_EQ, FirOperation.NOT_IDENTITY -> EqTrue
else -> throw IllegalArgumentException() else -> throw IllegalArgumentException()
} }
operandVariables.forEach { operandVariable -> operandVariables.forEach { operandVariable ->
flow = flow.addNotApprovedFact( flow = flow.addNotApprovedFact(
expressionVariable, UnapprovedFirDataFlowInfo( expressionVariable, UnapprovedFirDataFlowInfo(
eq(conditionValue), condition,
operandVariable, operandVariable,
FirDataFlowInfo(setOf(session.builtinTypes.anyType.coneTypeUnsafe()), emptySet()) FirDataFlowInfo(setOf(session.builtinTypes.anyType.coneTypeUnsafe()), emptySet())
) )
@@ -317,7 +317,7 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF
val node = graphBuilder.enterWhenBranchCondition(whenBranch).passFlow(false) val node = graphBuilder.enterWhenBranchCondition(whenBranch).passFlow(false)
val previousNode = node.previousNodes.single() val previousNode = node.previousNodes.single()
if (previousNode is WhenBranchConditionExitNode) { if (previousNode is WhenBranchConditionExitNode) {
node.flow = logicSystem.approveFactsInsideFlow(previousNode.falseCondition, node.flow) node.flow = logicSystem.approveFactsInsideFlow(previousNode.variable, EqFalse, node.flow)
} }
node.flow.freeze() node.flow.freeze()
} }
@@ -326,8 +326,7 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF
val node = graphBuilder.exitWhenBranchCondition(whenBranch).passFlow() val node = graphBuilder.exitWhenBranchCondition(whenBranch).passFlow()
val conditionVariable = getVariable(whenBranch.condition) val conditionVariable = getVariable(whenBranch.condition)
node.trueCondition = conditionVariable eq True node.variable = conditionVariable
node.falseCondition = conditionVariable eq False
} }
override fun exitWhenBranchResult(whenBranch: FirWhenBranch) { override fun exitWhenBranchResult(whenBranch: FirWhenBranch) {
@@ -495,7 +494,7 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF
leftNode.passFlow() leftNode.passFlow()
rightNode.passFlow(false) rightNode.passFlow(false)
val leftOperandVariable = getVariable(leftNode.previousNodes.first().fir) 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) { override fun exitBinaryAnd(binaryLogicExpression: FirBinaryLogicExpression) {
@@ -508,10 +507,10 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF
val andVariable = getVariable(binaryLogicExpression) val andVariable = getVariable(binaryLogicExpression)
val leftIsTrue = approveFact(leftVariable, True, flowFromRight) val leftIsTrue = approveFact(leftVariable, EqTrue, flowFromRight)
val leftIsFalse = approveFact(leftVariable, False, flowFromRight) val leftIsFalse = approveFact(leftVariable, EqFalse, flowFromRight)
val rightIsTrue = approveFact(rightVariable, True, flowFromRight) ?: mutableMapOf() val rightIsTrue = approveFact(rightVariable, EqTrue, flowFromRight) ?: mutableMapOf()
val rightIsFalse = approveFact(rightVariable, False, flowFromRight) val rightIsFalse = approveFact(rightVariable, EqFalse, flowFromRight)
flowFromRight.approvedFacts.forEach { (variable, info) -> flowFromRight.approvedFacts.forEach { (variable, info) ->
val actualInfo = flowFromLeft.approvedFacts[variable]?.let { info - it } ?: info val actualInfo = flowFromLeft.approvedFacts[variable]?.let { info - it } ?: info
@@ -520,12 +519,12 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF
logicSystem.andForVerifiedFacts(leftIsTrue, rightIsTrue)?.let { logicSystem.andForVerifiedFacts(leftIsTrue, rightIsTrue)?.let {
for ((variable, info) in it) { 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 { logicSystem.orForVerifiedFacts(leftIsFalse, rightIsFalse)?.let {
for ((variable, info) in it) { 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() } node.flow = flow.removeSyntheticVariable(leftVariable).removeSyntheticVariable(rightVariable).also { it.freeze() }
@@ -540,7 +539,7 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF
leftNode.passFlow() leftNode.passFlow()
rightNode.passFlow(false) rightNode.passFlow(false)
val leftOperandVariable = getVariable(leftNode.previousNodes.first().fir) 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) { override fun exitBinaryOr(binaryLogicExpression: FirBinaryLogicExpression) {
@@ -553,19 +552,19 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF
val orVariable = getVariable(binaryLogicExpression) val orVariable = getVariable(binaryLogicExpression)
val leftIsTrue = approveFact(leftVariable, True, flowFromLeft) val leftIsTrue = approveFact(leftVariable, EqTrue, flowFromLeft)
val leftIsFalse = approveFact(leftVariable, False, flowFromLeft) val leftIsFalse = approveFact(leftVariable, EqFalse, flowFromLeft)
val rightIsTrue = approveFact(rightVariable, True, flowFromRight) val rightIsTrue = approveFact(rightVariable, EqTrue, flowFromRight)
val rightIsFalse = approveFact(rightVariable, False, flowFromRight) val rightIsFalse = approveFact(rightVariable, EqFalse, flowFromRight)
logicSystem.orForVerifiedFacts(leftIsTrue, rightIsTrue)?.let { logicSystem.orForVerifiedFacts(leftIsTrue, rightIsTrue)?.let {
for ((variable, info) in it) { 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 { logicSystem.andForVerifiedFacts(leftIsFalse, rightIsFalse)?.let {
for ((variable, info) in it) { 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() } 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>? = private fun approveFact(variable: DataFlowVariable, condition: Condition, flow: Flow): MutableMap<DataFlowVariable, FirDataFlowInfo>? =
logicSystem.approveFact(variable eq value, flow) logicSystem.approveFact(variable, condition, flow)
private fun FirBinaryLogicExpression.getVariables(): Pair<DataFlowVariable, DataFlowVariable> = private fun FirBinaryLogicExpression.getVariables(): Pair<DataFlowVariable, DataFlowVariable> =
getVariable(leftOperand) to getVariable(rightOperand) getVariable(leftOperand) to getVariable(rightOperand)
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.render import org.jetbrains.kotlin.fir.types.render
data class UnapprovedFirDataFlowInfo( data class UnapprovedFirDataFlowInfo(
val condition: ConditionRHS, val condition: Condition,
val variable: DataFlowVariable, val variable: DataFlowVariable,
val info: FirDataFlowInfo val info: FirDataFlowInfo
) { ) {
@@ -69,8 +69,8 @@ class LogicSystem(private val context: DataFlowInferenceContext) {
return map return map
} }
fun approveFactsInsideFlow(proof: Condition, flow: Flow): Flow { fun approveFactsInsideFlow(variable: DataFlowVariable, condition: Condition, flow: Flow): Flow {
val notApprovedFacts: Set<UnapprovedFirDataFlowInfo> = flow.notApprovedFacts[proof.variable] val notApprovedFacts: Set<UnapprovedFirDataFlowInfo> = flow.notApprovedFacts[variable]
if (notApprovedFacts.isEmpty()) { if (notApprovedFacts.isEmpty()) {
return flow return flow
} }
@@ -78,7 +78,7 @@ class LogicSystem(private val context: DataFlowInferenceContext) {
val flow = flow.copyForBuilding() val flow = flow.copyForBuilding()
val newFacts = HashMultimap.create<DataFlowVariable, FirDataFlowInfo>() val newFacts = HashMultimap.create<DataFlowVariable, FirDataFlowInfo>()
notApprovedFacts.forEach { notApprovedFacts.forEach {
if (it.condition == proof.rhs) { if (it.condition == condition) {
newFacts.put(it.variable, it.info) newFacts.put(it.variable, it.info)
} }
} }
@@ -93,14 +93,14 @@ class LogicSystem(private val context: DataFlowInferenceContext) {
return flow return flow
} }
fun approveFact(proof: Condition, flow: Flow): MutableMap<DataFlowVariable, FirDataFlowInfo> { fun approveFact(variable: DataFlowVariable, condition: Condition, flow: Flow): MutableMap<DataFlowVariable, FirDataFlowInfo> {
val notApprovedFacts: Set<UnapprovedFirDataFlowInfo> = flow.notApprovedFacts[proof.variable] val notApprovedFacts: Set<UnapprovedFirDataFlowInfo> = flow.notApprovedFacts[variable]
if (notApprovedFacts.isEmpty()) { if (notApprovedFacts.isEmpty()) {
return mutableMapOf() return mutableMapOf()
} }
val newFacts = HashMultimap.create<DataFlowVariable, FirDataFlowInfo>() val newFacts = HashMultimap.create<DataFlowVariable, FirDataFlowInfo>()
notApprovedFacts.forEach { notApprovedFacts.forEach {
if (it.condition == proof.rhs) { if (it.condition == condition) {
newFacts.put(it.variable, it.info) 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.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.expressions.* 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) { class ControlFlowGraph(val name: String) {
val nodes = mutableListOf<CFGNode<*>>() 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 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 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 { class WhenBranchConditionExitNode(owner: ControlFlowGraph, override val fir: FirWhenBranch, level: Int) : CFGNode<FirWhenBranch>(owner, level), ExitNode {
lateinit var trueCondition: Condition lateinit var variable: DataFlowVariable
lateinit var falseCondition: Condition
} }
class WhenBranchResultExitNode(owner: ControlFlowGraph, override val fir: FirWhenBranch, level: Int) : CFGNode<FirWhenBranch>(owner, level) class WhenBranchResultExitNode(owner: ControlFlowGraph, override val fir: FirWhenBranch, level: Int) : CFGNode<FirWhenBranch>(owner, level)