FIR DFA: fix handling of equality operation

This commit is contained in:
Tianyu Geng
2021-07-23 22:56:56 -07:00
committed by teamcityserver
parent 0026560bd7
commit e495c722c7
4 changed files with 44 additions and 20 deletions
@@ -483,26 +483,50 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
} }
// propagating facts for (... == true) and (... == false) // propagating facts for (... == true) and (... == false)
if (const.kind == ConstantValueKind.Boolean) { when (const.kind) {
val constValue = const.value as Boolean ConstantValueKind.Boolean -> {
val shouldInvert = isEq xor constValue val constValue = const.value as Boolean
val shouldInvert = isEq xor constValue
logicSystem.translateVariableFromConditionInStatements( logicSystem.translateVariableFromConditionInStatements(
flow, flow,
operandVariable, operandVariable,
expressionVariable, expressionVariable,
shouldRemoveOriginalStatements = operandVariable.isSynthetic() shouldRemoveOriginalStatements = operandVariable.isSynthetic()
) { ) {
when (it.condition.operation) { when (it.condition.operation) {
Operation.EqNull, Operation.NotEqNull -> { // Whatever the result is after comparing operandVariable with `true` or `false` cannot let you imply effects that apply
(expressionVariable eq isEq) implies (it.effect) // when the operandVariable is null. Hence we return null here.
} Operation.EqNull -> null
Operation.EqTrue, Operation.EqFalse -> { Operation.NotEqNull -> {
if (shouldInvert) (it.condition.invert()) implies (it.effect) (expressionVariable eq isEq) implies (it.effect)
else it }
Operation.EqTrue, Operation.EqFalse -> {
if (shouldInvert) (it.condition.invert()) implies (it.effect)
else it
}
} }
} }
} }
ConstantValueKind.Null -> {
logicSystem.translateVariableFromConditionInStatements(
flow,
operandVariable,
expressionVariable,
shouldRemoveOriginalStatements = operandVariable.isSynthetic()
) {
when (it.condition.operation) {
Operation.EqNull -> (expressionVariable eq isEq) implies (it.effect)
Operation.NotEqNull -> (expressionVariable eq !isEq) implies (it.effect)
// Whatever the result is after comparing operandVariable with `null` cannot let you imply effects that apply when the
// operandVariable is true or false.
Operation.EqTrue, Operation.EqFalse -> null
}
}
}
else -> {
// Inconclusive if the user code compares with other constants.
}
} }
} }
@@ -47,7 +47,7 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
newVariable: DataFlowVariable, newVariable: DataFlowVariable,
shouldRemoveOriginalStatements: Boolean, shouldRemoveOriginalStatements: Boolean,
filter: (Implication) -> Boolean = { true }, filter: (Implication) -> Boolean = { true },
transform: (Implication) -> Implication = { it }, transform: (Implication) -> Implication? = { it },
) )
abstract fun approveStatementsInsideFlow( abstract fun approveStatementsInsideFlow(
@@ -297,11 +297,11 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
newVariable: DataFlowVariable, newVariable: DataFlowVariable,
shouldRemoveOriginalStatements: Boolean, shouldRemoveOriginalStatements: Boolean,
filter: (Implication) -> Boolean, filter: (Implication) -> Boolean,
transform: (Implication) -> Implication transform: (Implication) -> Implication?
) { ) {
with(flow) { with(flow) {
val statements = logicStatements[originalVariable]?.takeIf { it.isNotEmpty() } ?: return val statements = logicStatements[originalVariable]?.takeIf { it.isNotEmpty() } ?: return
val newStatements = statements.filter(filter).map { val newStatements = statements.filter(filter).mapNotNull {
val newStatement = OperationStatement(newVariable, it.condition.operation) implies it.effect val newStatement = OperationStatement(newVariable, it.condition.operation) implies it.effect
transform(newStatement) transform(newStatement)
}.toPersistentList() }.toPersistentList()
@@ -116,7 +116,7 @@ fun case_5(value_1: Number?, value_2: String?) {
fun case_6(value_1: Number, value_2: String?, value_3: Any?) { fun case_6(value_1: Number, value_2: String?, value_3: Any?) {
when (value_3.case_6(value_1, value_2)) { when (value_3.case_6(value_1, value_2)) {
true -> { true -> {
println(value_3.equals("")) println(value_3<!UNSAFE_CALL!>.<!>equals(""))
println(value_2<!UNSAFE_CALL!>.<!>length) println(value_2<!UNSAFE_CALL!>.<!>length)
} }
false -> { false -> {