FIR DFA: slightly simplify {and,or}ForTypeStatements

And use them less in boolean expression analysis. This uncovers a fun
new case that doesn't work:

    interface I { val x: String }
    class C(override val x: String) : I
    class D(override val x: String) : I

    fun foo(x: Any?) {
      if (x is D || (x as C).x != "") {
        println(x.x.length) // actually OK (x is D || x is C => x is I)
      }
    }
This commit is contained in:
pyos
2022-11-08 18:45:47 +01:00
committed by teamcity
parent ac0137f45f
commit 39f6b50836
5 changed files with 50 additions and 81 deletions
@@ -65,38 +65,37 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
rightVariable: DataFlowVariable,
): InfoForBooleanOperator
abstract fun approveStatementsTo(
destination: MutableTypeStatements,
abstract fun approveOperationStatement(
flow: FLOW,
approvedStatement: OperationStatement,
statements: Collection<Implication>,
)
statementsForVariable: Collection<Implication>?
): TypeStatements
fun orForTypeStatements(left: TypeStatements, right: TypeStatements): MutableTypeStatements {
if (left.isEmpty() || right.isEmpty()) return mutableMapOf()
val map = mutableMapOf<RealVariable, MutableTypeStatement>()
for (variable in left.keys.intersect(right.keys)) {
val leftStatement = left.getValue(variable)
val rightStatement = right.getValue(variable)
map[variable] = or(listOf(leftStatement, rightStatement))
fun orForTypeStatements(left: TypeStatements, right: TypeStatements): TypeStatements = when {
left.isEmpty() -> left
right.isEmpty() -> right
else -> buildMap {
for ((variable, leftStatement) in left) {
put(variable, or(listOf(leftStatement, right[variable] ?: continue)))
}
}
return map
}
fun andForTypeStatements(left: TypeStatements, right: TypeStatements): MutableTypeStatements {
if (left.isEmpty() && right.isEmpty()) return mutableMapOf()
val map = left.asMutableStatements()
for ((variable, rightStatement) in right) {
map[variable] = and(listOfNotNull(map[variable], rightStatement))
fun andForTypeStatements(left: TypeStatements, right: TypeStatements): TypeStatements = when {
left.isEmpty() -> right
right.isEmpty() -> left
else -> left.toMutableMap().apply {
for ((variable, rightStatement) in right) {
put(variable, { rightStatement }, { and(listOf(it, rightStatement)) })
}
}
return map
}
// ------------------------------- Util functions -------------------------------
private fun foldStatements(statements: Collection<TypeStatement>, all: Boolean): MutableTypeStatement {
private fun foldStatements(statements: Collection<TypeStatement>, all: Boolean): TypeStatement {
require(statements.isNotEmpty())
statements.singleOrNull()?.let { return it.asMutableStatement() }
statements.singleOrNull()?.let { return it }
val variable = statements.first().variable
assert(statements.all { it.variable == variable })
// TypeStatement(variable, exactType, exactNotType) =
@@ -127,23 +126,13 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
}.takeIf { !onlyInputTypes || it in intersected }
}
protected fun and(statements: Collection<TypeStatement>): MutableTypeStatement =
protected fun and(statements: Collection<TypeStatement>): TypeStatement =
foldStatements(statements, all = true)
protected fun or(statements: Collection<TypeStatement>): MutableTypeStatement =
protected fun or(statements: Collection<TypeStatement>): TypeStatement =
foldStatements(statements, all = false)
}
fun <FLOW : Flow> LogicSystem<FLOW>.approveOperationStatement(
flow: FLOW,
approvedStatement: OperationStatement,
statements: Collection<Implication>,
): MutableTypeStatements {
return mutableMapOf<RealVariable, MutableTypeStatement>().apply {
approveStatementsTo(this, flow, approvedStatement, statements)
}
}
/*
* used for:
* 1. val b = x is String
@@ -339,18 +339,13 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
}
}
override fun approveStatementsTo(
destination: MutableTypeStatements,
override fun approveOperationStatement(
flow: PersistentFlow,
approvedStatement: OperationStatement,
statements: Collection<Implication>
) {
val approveOperationStatements =
approveOperationStatementsInternal(flow, approvedStatement, statements, shouldRemoveSynthetics = false)
approveOperationStatements.asMap().forEach { (variable, infos) ->
destination.put(variable, { and(infos) }, { and(listOf(it) + infos) })
}
}
statementsForVariable: Collection<Implication>?
): TypeStatements =
approveOperationStatementsInternal(flow, approvedStatement, statementsForVariable, shouldRemoveSynthetics = false)
.asMap().mapValues { and(it.value) }
override fun collectInfoForBooleanOperator(
leftFlow: PersistentFlow,
@@ -35,9 +35,6 @@ fun Implication.invertCondition(): Implication = Implication(condition.invert(),
typealias TypeStatements = Map<RealVariable, TypeStatement>
typealias MutableTypeStatements = MutableMap<RealVariable, MutableTypeStatement>
fun TypeStatements.asMutableStatements(): MutableTypeStatements =
mapValuesTo(mutableMapOf()) { it.value.asMutableStatement() }
// --------------------------------------- DSL ---------------------------------------
infix fun DataFlowVariable.eq(constant: Boolean?): OperationStatement {