From cfa48b5cc0449fc10788c13333f44c58bfc36857 Mon Sep 17 00:00:00 2001 From: Brian Norman Date: Thu, 16 Nov 2023 10:27:32 -0600 Subject: [PATCH] [FIR] Add null implications to both sides of equality when appropriate When both sides of an equality expression are null or Nothing?, only the right side is receiving implications within the data-flow. Make sure the left side has implications add as well. This is important for boolean conditions when implications from both sides need to be combined. ^KT-63535 Fixed --- .../fir/resolve/dfa/FirDataFlowAnalyzer.kt | 6 +- .../diagnostics/notLinked/dfa/pos/6.fir.kt | 86 +++++++++---------- 2 files changed, 47 insertions(+), 45 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt index af389137a93..703e74f79c1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt @@ -431,8 +431,10 @@ abstract class FirDataFlowAnalyzer( node.mergeIncomingFlow { _, flow -> when { leftConst != null && rightConst != null -> return@mergeIncomingFlow - leftIsNull -> processEqNull(flow, equalityOperatorCall, rightOperand, operation.isEq()) - rightIsNull -> processEqNull(flow, equalityOperatorCall, leftOperand, operation.isEq()) + leftIsNull || rightIsNull -> { + if (leftIsNull) processEqNull(flow, equalityOperatorCall, rightOperand, operation.isEq()) + if (rightIsNull) processEqNull(flow, equalityOperatorCall, leftOperand, operation.isEq()) + } leftConst != null -> processEqConst(flow, equalityOperatorCall, rightOperand, leftConst, operation.isEq()) rightConst != null -> processEqConst(flow, equalityOperatorCall, leftOperand, rightConst, operation.isEq()) else -> processEq(flow, lhsExitNode.flow, equalityOperatorCall, leftOperand, rightOperand, operation) diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/6.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/6.fir.kt index 28ffd634a1b..e1eba841726 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/6.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/6.fir.kt @@ -47,8 +47,8 @@ fun case_1(x: Any?) { fun case_2(x: Nothing?) { val y = null if (x !== y) { - x - x.hashCode() + x + x.hashCode() } } @@ -129,16 +129,16 @@ fun case_7(x: EmptyObject?) { val y = null if (x != y || x != y) { - x - x.equals(null) - x.propT - x.propAny - x.propNullableT - x.propNullableAny - x.funT() - x.funAny() - x.funNullableT() - x.funNullableAny() + x + x.equals(null) + x.propT + x.propAny + x.propNullableT + x.propNullableAny + x.funT() + x.funAny() + x.funNullableT() + x.funNullableAny() } } @@ -211,16 +211,16 @@ fun case_11(x: TypealiasNullableString?, y: TypealiasNu if (y != z) { if (nullableStringProperty == z) { if (u != z || u != v) { - x - x.equals(null) - x.propT - x.propAny - x.propNullableT - x.propNullableAny - x.funT() - x.funAny() - x.funNullableT() - x.funNullableAny() + x + x.equals(null) + x.propT + x.propAny + x.propNullableT + x.propNullableAny + x.funT() + x.funAny() + x.funNullableT() + x.funNullableAny() } } } @@ -448,16 +448,16 @@ fun case_23(a: ((Float) -> Int?)?, b: Float?, z: Nothing?) { if (a != z && b !== z && b !== z) { val x = a(b) if (x != z || x !== implicitNullableNothingProperty) { - x - x.equals(null) - x.propT - x.propAny - x.propNullableT - x.propNullableAny - x.funT() - x.funAny() - x.funNullableT() - x.funNullableAny() + x + x.equals(null) + x.propT + x.propAny + x.propNullableT + x.propNullableAny + x.funT() + x.funAny() + x.funNullableT() + x.funNullableAny() } } } @@ -497,7 +497,7 @@ fun case_25(b: Boolean, z: Nothing?) { val y = if (b) x else z if (y !== z || y != implicitNullableNothingProperty) { - val z1 = ?")!>y() + val z1 = ?")!>y() if (z1 != z && implicitNullableNothingProperty !== z1) { ? & ")!>z1.a @@ -663,16 +663,16 @@ fun case_33(a: ((Float) -> Int?)?, b: Float?, c: Boolean?) { if (x == z == true && x === z || (c != z && !c)) { } else { - x - x.equals(null) - x.propT - x.propAny - x.propNullableT - x.propNullableAny - x.funT() - x.funAny() - x.funNullableT() - x.funNullableAny() + x + x.equals(null) + x.propT + x.propAny + x.propNullableT + x.propNullableAny + x.funT() + x.funAny() + x.funNullableT() + x.funNullableAny() } } }