FIR DFA: remove approved and impossible statements from flows

This commit is contained in:
pyos
2022-11-10 17:41:41 +01:00
committed by teamcity
parent 5796f0eb07
commit 98f52f13ef
4 changed files with 48 additions and 73 deletions
@@ -26,16 +26,16 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
flow: FLOW,
originalVariable: DataFlowVariable,
newVariable: DataFlowVariable,
shouldRemoveOriginalStatements: Boolean,
shouldRemoveOriginalStatements: Boolean = originalVariable.isSynthetic(),
filter: (Implication) -> Boolean = { true },
transform: (Implication) -> Implication? = { it },
)
// This does *not* commit the results to the flow (but it does mutate the flow if shouldRemoveSynthetics=true)
// This does *not* commit the results to the flow (but it does mutate the flow if removeApprovedOrImpossible=true)
abstract fun approveOperationStatement(
flow: FLOW,
approvedStatement: OperationStatement,
shouldRemoveSynthetics: Boolean = false
removeApprovedOrImpossible: Boolean = false
): TypeStatements
protected abstract fun ConeKotlinType.isAcceptableForSmartcast(): Boolean
@@ -90,26 +90,3 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
protected fun or(statements: Collection<TypeStatement>): TypeStatement =
statements.singleOrNew { unifyTypes(statements.map { it.exactType })?.let { mutableSetOf(it) } ?: mutableSetOf() }
}
/*
* used for:
* 1. val b = x is String
* 2. b = x is String
* 3. !b | b.not() for Booleans
*/
fun <F : Flow> LogicSystem<F>.replaceVariableFromConditionInStatements(
flow: F,
originalVariable: DataFlowVariable,
newVariable: DataFlowVariable,
filter: (Implication) -> Boolean = { true },
transform: (Implication) -> Implication = { it },
) {
translateVariableFromConditionInStatements(
flow,
originalVariable,
newVariable,
shouldRemoveOriginalStatements = true,
filter,
transform,
)
}
@@ -256,7 +256,7 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
override fun approveOperationStatement(
flow: PersistentFlow,
approvedStatement: OperationStatement,
shouldRemoveSynthetics: Boolean,
removeApprovedOrImpossible: Boolean,
): TypeStatements {
val approvedTypeStatements: ArrayListMultimap<RealVariable, TypeStatement> = ArrayListMultimap.create()
val queue = LinkedList<OperationStatement>().apply { this += approvedStatement }
@@ -266,17 +266,21 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
// Defense from cycles in facts
if (!approved.add(next)) continue
val variable = next.variable
val statements = flow.logicStatements[variable]?.takeIf { it.isNotEmpty() } ?: continue
if (shouldRemoveSynthetics && variable.isSynthetic()) {
flow.logicStatements -= variable
}
for (statement in statements) {
if (statement.condition == next) {
when (val effect = statement.effect) {
val statements = flow.logicStatements[variable] ?: continue
val stillUnknown = statements.removeAll {
val knownValue = it.condition.operation.valueIfKnown(next.operation)
if (knownValue == true) {
when (val effect = it.effect) {
is OperationStatement -> queue += effect
is TypeStatement -> approvedTypeStatements.put(effect.variable, effect)
}
}
removeApprovedOrImpossible && knownValue != null
}
if (stillUnknown.isEmpty()) {
flow.logicStatements -= variable
} else if (stillUnknown != statements) {
flow.logicStatements = flow.logicStatements.put(variable, stillUnknown)
}
}
return approvedTypeStatements.asMap().mapValues { and(it.value) }
@@ -62,6 +62,12 @@ enum class Operation {
NotEqNull -> EqNull
}
fun valueIfKnown(given: Operation): Boolean? = when (this) {
EqTrue, EqFalse -> if (given == NotEqNull) null else given == this
EqNull -> given == EqNull
NotEqNull -> given == NotEqNull
}
override fun toString(): String = when (this) {
EqTrue -> "== True"
EqFalse -> "== False"