FIR DFA: do not remove statements about LHS of !!
Value equality statements about the result also propagate to left-hand side, so these statements can still be useful.
This commit is contained in:
+6
-21
@@ -678,30 +678,14 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
val (node, unionNode) = graphBuilder.exitCheckNotNullCall(checkNotNullCall, callCompleted)
|
val (node, unionNode) = graphBuilder.exitCheckNotNullCall(checkNotNullCall, callCompleted)
|
||||||
node.mergeIncomingFlow()
|
node.mergeIncomingFlow()
|
||||||
|
|
||||||
checkNotNullCall.argument.propagateNotNullInfo(node)
|
val argumentVariable = variableStorage.getOrCreateVariable(node.previousFlow, checkNotNullCall.argument)
|
||||||
|
node.flow.assumeNotNull(argumentVariable, shouldForkFlow = false, shouldRemoveSynthetics = false)
|
||||||
|
|
||||||
unionNode?.let { unionFlowFromArguments(it) }
|
unionNode?.let { unionFlowFromArguments(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirExpression.propagateNotNullInfo(node: CFGNode<*>) {
|
|
||||||
val symbol = this.symbol
|
|
||||||
if (symbol != null) {
|
|
||||||
variableStorage.getOrCreateRealVariable(node.previousFlow, symbol, this)?.let { operandVariable ->
|
|
||||||
node.flow.assumeNotNull(operandVariable, shouldForkFlow = false, shouldRemoveSynthetics = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
when (this) {
|
|
||||||
is FirSafeCallExpression -> receiver.propagateNotNullInfo(node)
|
|
||||||
is FirTypeOperatorCall -> {
|
|
||||||
if (operation == FirOperation.AS || operation == FirOperation.SAFE_AS) {
|
|
||||||
argument.propagateNotNullInfo(node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun FLOW.assumeNotNull(variable: DataFlowVariable, shouldForkFlow: Boolean, shouldRemoveSynthetics: Boolean): FLOW =
|
private fun FLOW.assumeNotNull(variable: DataFlowVariable, shouldForkFlow: Boolean, shouldRemoveSynthetics: Boolean): FLOW =
|
||||||
logicSystem.approveStatementsInsideFlow(this, variable notEq null, shouldForkFlow, shouldRemoveSynthetics,).also {
|
logicSystem.approveStatementsInsideFlow(this, variable notEq null, shouldForkFlow, shouldRemoveSynthetics).also {
|
||||||
if (variable is RealVariable) {
|
if (variable is RealVariable) {
|
||||||
it.addTypeStatement(variable typeEq any andTypeNotEq nullableNothing)
|
it.addTypeStatement(variable typeEq any andTypeNotEq nullableNothing)
|
||||||
}
|
}
|
||||||
@@ -1380,7 +1364,8 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
node.mergeIncomingFlow()
|
node.mergeIncomingFlow()
|
||||||
mergePostponedLambdaExitsNode?.mergeIncomingFlow()
|
mergePostponedLambdaExitsNode?.mergeIncomingFlow()
|
||||||
if (isLhsNotNull) {
|
if (isLhsNotNull) {
|
||||||
elvisExpression.lhs.propagateNotNullInfo(node)
|
val lhsVariable = variableStorage.getOrCreateVariable(node.previousFlow, elvisExpression.lhs)
|
||||||
|
node.flow.assumeNotNull(lhsVariable, shouldForkFlow = false, shouldRemoveSynthetics = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!components.session.languageVersionSettings.supportsFeature(LanguageFeature.BooleanElvisBoundSmartCasts)) return
|
if (!components.session.languageVersionSettings.supportsFeature(LanguageFeature.BooleanElvisBoundSmartCasts)) return
|
||||||
@@ -1396,7 +1381,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
val lhsVariable = variableStorage.getOrCreateVariable(flow, lhs)
|
val lhsVariable = variableStorage.getOrCreateVariable(flow, lhs)
|
||||||
|
|
||||||
val value = rhs.value as Boolean
|
val value = rhs.value as Boolean
|
||||||
flow.addImplication(elvisVariable.eq(!value) implies (lhsVariable.notEq(null)))
|
flow.addImplication((elvisVariable eq !value) implies (lhsVariable notEq null))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -63,7 +63,7 @@ fun case_2(value_1: Int?) {
|
|||||||
// TESTCASE NUMBER: 3
|
// TESTCASE NUMBER: 3
|
||||||
fun case_3(value_1: Int?) {
|
fun case_3(value_1: Int?) {
|
||||||
if (contracts.case_3(value_1)!!) {
|
if (contracts.case_3(value_1)!!) {
|
||||||
value_1<!UNSAFE_CALL!>.<!>inv()
|
value_1.inv()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ inline fun <reified T : CharSequence>case_3(x: Any?) {
|
|||||||
// TESTCASE NUMBER: 4
|
// TESTCASE NUMBER: 4
|
||||||
inline fun <reified T : CharSequence>case_4(x: Any?) {
|
inline fun <reified T : CharSequence>case_4(x: Any?) {
|
||||||
(x as? T)!!
|
(x as? T)!!
|
||||||
if (x is T?) {
|
if (<!USELESS_IS_CHECK!>x is T?<!>) {
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>.length
|
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>.length
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>.get(0)
|
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>.get(0)
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ inline fun <reified T : CharSequence>case_3(x: Any?) {
|
|||||||
// TESTCASE NUMBER: 4
|
// TESTCASE NUMBER: 4
|
||||||
inline fun <reified T : CharSequence>case_4(x: Any?) {
|
inline fun <reified T : CharSequence>case_4(x: Any?) {
|
||||||
(x as? T)!!
|
(x as? T)!!
|
||||||
if (x is T?) {
|
if (<!USELESS_IS_CHECK!>x is T?<!>) {
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>.length
|
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>.length
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>.get(0)
|
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>.get(0)
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ inline fun <reified T : CharSequence>case_3(x: Any?) {
|
|||||||
// TESTCASE NUMBER: 4
|
// TESTCASE NUMBER: 4
|
||||||
inline fun <reified T : CharSequence>case_4(x: Any?) {
|
inline fun <reified T : CharSequence>case_4(x: Any?) {
|
||||||
(x as? T)!!
|
(x as? T)!!
|
||||||
if (x is T?) {
|
if (<!USELESS_IS_CHECK!>x is T?<!>) {
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>.length
|
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>.length
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>.get(0)
|
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & T?!!")!>x<!>.get(0)
|
||||||
|
|||||||
Reference in New Issue
Block a user