FIR DFA: extract approveStatementsInsideFlow(variable notEq null)

I'm not sure how this fixes a test. Magic!
This commit is contained in:
pyos
2022-11-08 15:53:23 +01:00
committed by teamcity
parent 623dfdd5a3
commit 1ff968eca2
2 changed files with 13 additions and 37 deletions
@@ -447,12 +447,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
flow.addTypeStatement(operandVariable typeEq type)
}
if (!type.canBeNull) {
logicSystem.approveStatementsInsideFlow(
flow,
operandVariable notEq null,
shouldRemoveSynthetics = true,
shouldForkFlow = false
)
flow.assumeNotNull(operandVariable, shouldForkFlow = false, shouldRemoveSynthetics = true)
} else {
val expressionVariable = variableStorage.createSyntheticVariable(typeOperatorCall)
flow.addImplication((expressionVariable notEq null) implies (operandVariable notEq null))
@@ -525,9 +520,6 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
val operandVariable = variableStorage.getOrCreateVariable(node.previousFlow, operand)
// expression == const -> expression != null
flow.addImplication((expressionVariable eq isEq) implies (operandVariable notEq null))
if (operandVariable.isReal()) {
flow.addImplication((expressionVariable eq isEq) implies (operandVariable typeEq any))
}
// propagating facts for (... == true) and (... == false)
when (const.kind) {
@@ -691,17 +683,11 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
unionNode?.let { unionFlowFromArguments(it) }
}
fun FirExpression.propagateNotNullInfo(node: CFGNode<*>) {
private fun FirExpression.propagateNotNullInfo(node: CFGNode<*>) {
val symbol = this.symbol
if (symbol != null) {
variableStorage.getOrCreateRealVariable(node.previousFlow, symbol, this)?.let { operandVariable ->
node.flow.addTypeStatement(operandVariable typeEq any)
logicSystem.approveStatementsInsideFlow(
node.flow,
operandVariable notEq null,
shouldRemoveSynthetics = true,
shouldForkFlow = false
)
node.flow.assumeNotNull(operandVariable, shouldForkFlow = false, shouldRemoveSynthetics = true)
}
}
when (this) {
@@ -714,6 +700,13 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
}
}
private fun FLOW.assumeNotNull(variable: DataFlowVariable, shouldForkFlow: Boolean, shouldRemoveSynthetics: Boolean): FLOW =
logicSystem.approveStatementsInsideFlow(this, variable notEq null, shouldForkFlow, shouldRemoveSynthetics,).also {
if (variable is RealVariable) {
it.addTypeStatement(variable typeEq any andTypeNotEq nullableNothing)
}
}
// ----------------------------------- When -----------------------------------
fun enterWhenExpression(whenExpression: FirWhenExpression) {
@@ -943,12 +936,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
}
flow.addTypeStatement(variable typeEq type)
}
flow = logicSystem.approveStatementsInsideFlow(
flow,
variable notEq null,
shouldFork,
shouldRemoveSynthetics = false
)
flow = flow.assumeNotNull(variable, shouldFork, shouldRemoveSynthetics = false)
}
node.flow = flow
@@ -966,9 +954,6 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
is SyntheticVariable -> variableStorage.getOrCreateVariable(flow, safeCall.receiver)
}
flow.addImplication((variable notEq null) implies (receiverVariable notEq null))
if (receiverVariable.isReal()) {
flow.addImplication((variable notEq null) implies (receiverVariable typeEq any))
}
}
fun exitResolvedQualifierNode(resolvedQualifier: FirResolvedQualifier) {
@@ -1379,16 +1364,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
lhsExitNode.mergeIncomingFlow()
val flow = lhsExitNode.flow
val lhsVariable = variableStorage.getOrCreateVariable(flow, elvisExpression.lhs)
lhsIsNotNullNode.flow = logicSystem.approveStatementsInsideFlow(
flow,
lhsVariable notEq null,
shouldForkFlow = true,
shouldRemoveSynthetics = false
).also {
if (lhsVariable.isReal()) {
it.addTypeStatement(lhsVariable typeEq any)
}
}
lhsIsNotNullNode.flow = flow.assumeNotNull(lhsVariable, shouldForkFlow = true, shouldRemoveSynthetics = false)
rhsEnterNode.flow = logicSystem.approveStatementsInsideFlow(
flow,
lhsVariable eq null,
@@ -8,7 +8,7 @@ fun calc(x: String?, y: String?): Int {
// x is not null in condition but we do not see it yet
} while (x.length > 0)
// y is nullable because of break
y.length
y<!UNSAFE_CALL!>.<!>length
// x is not null, at least in theory
return x.length
}