FIR checker: SENSELESS_(COMPARISON|NULL_IN_WHEN)

Currently DFA does not set "definitely equal to null" for access to variables that got assigned `null`. For example, FIR should mark the following line as SENSELESS_COMPARISON due to `s = null` above.
 https://github.com/JetBrains/kotlin/blob/d1531f9cdd5852352c0133198706125dc63b6007/compiler/testData/diagnostics/tests/smartCasts/alwaysNull.fir.kt#L6

The problem is at https://github.com/JetBrains/kotlin/blob/7e9f27436a77de1c76e3705da7aa1fbe8938336b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt#L1104

For null assignment, ideally the type should be `Nothing?`. This is
addressed in a followup commit instead.
This commit is contained in:
Tianyu Geng
2021-07-20 09:46:18 -07:00
committed by teamcityserver
parent 4726dcce40
commit c7272f6986
108 changed files with 1410 additions and 1485 deletions
@@ -157,29 +157,29 @@ fun <T> T?.case_22_3(): Boolean? {
// TESTCASE NUMBER: 23
fun <T : Number?> T.case_23_1(): Boolean {
contract { returns(false) implies (this@case_23_1 !is Int || this@case_23_1 == null) }
return !(this@case_23_1 !is Int || this@case_23_1 == null)
return !(this@case_23_1 !is Int || <!SENSELESS_COMPARISON!>this@case_23_1 == null<!>)
}
fun <T : Number?> T.case_23_2(): Boolean? {
contract { returnsNotNull() implies (this@case_23_2 !is Int || this@case_23_2 == null) }
return if (this@case_23_2 !is Int || this@case_23_2 == null) true else null
return if (this@case_23_2 !is Int || <!SENSELESS_COMPARISON!>this@case_23_2 == null<!>) true else null
}
fun <T : Number?> T.case_23_3(): Boolean? {
contract { returns(null) implies (this@case_23_3 !is Int || this@case_23_3 == null) }
return if (this@case_23_3 !is Int || this@case_23_3 == null) null else true
return if (this@case_23_3 !is Int || <!SENSELESS_COMPARISON!>this@case_23_3 == null<!>) null else true
}
// TESTCASE NUMBER: 24
inline fun <reified T : Any?> T?.case_24_1(): Boolean {
contract { returns(false) implies (this@case_24_1 !is Number || this@case_24_1 !is Int || this@case_24_1 == null) }
return !(this@case_24_1 !is Number || this@case_24_1 !is Int || this@case_24_1 == null)
return !(this@case_24_1 !is Number || this@case_24_1 !is Int || <!SENSELESS_COMPARISON!>this@case_24_1 == null<!>)
}
inline fun <reified T : Any?> T?.case_24_2(): Boolean? {
contract { returnsNotNull() implies (this@case_24_2 !is Number || this@case_24_2 !is Int || this@case_24_2 == null) }
return if (this@case_24_2 !is Number || this@case_24_2 !is Int || this@case_24_2 == null) true else null
return if (this@case_24_2 !is Number || this@case_24_2 !is Int || <!SENSELESS_COMPARISON!>this@case_24_2 == null<!>) true else null
}
inline fun <reified T : Any?> T?.case_24_3(): Boolean? {
contract { returns(null) implies (this@case_24_3 !is Number || this@case_24_3 !is Int || this@case_24_3 == null) }
return if (this@case_24_3 !is Number || this@case_24_3 !is Int || this@case_24_3 == null) null else true
return if (this@case_24_3 !is Number || this@case_24_3 !is Int || <!SENSELESS_COMPARISON!>this@case_24_3 == null<!>) null else true
}
// TESTCASE NUMBER: 25
@@ -15,13 +15,13 @@ fun <T> T?.case_1() {
// TESTCASE NUMBER: 2
fun <T : Number?> T.case_2() {
contract { returns() implies (this@case_2 !is Int || this@case_2 == null) }
if (!(this@case_2 !is Int || this@case_2 == null)) throw Exception()
if (!(this@case_2 !is Int || <!SENSELESS_COMPARISON!>this@case_2 == null<!>)) throw Exception()
}
// TESTCASE NUMBER: 3
inline fun <reified T : Any?> T?.case_3() {
contract { returns() implies (this@case_3 !is Number || this@case_3 !is Int || this@case_3 == null) }
if (!(this@case_3 !is Number || this@case_3 !is Int || this@case_3 == null)) throw Exception()
if (!(this@case_3 !is Number || this@case_3 !is Int || <!SENSELESS_COMPARISON!>this@case_3 == null<!>)) throw Exception()
}
// TESTCASE NUMBER: 4
@@ -45,37 +45,37 @@ fun <T> T?.case_4_4(): Boolean? {
// TESTCASE NUMBER: 5
fun <T : Number?> T.case_5_1(): Boolean {
contract { returns(true) implies (this@case_5_1 !is Int || this@case_5_1 == null) }
return this@case_5_1 !is Int || this@case_5_1 == null
return this@case_5_1 !is Int || <!SENSELESS_COMPARISON!>this@case_5_1 == null<!>
}
fun <T : Number?> T.case_5_2(): Boolean {
contract { returns(false) implies (this@case_5_2 !is Int || this@case_5_2 == null) }
return !(this@case_5_2 !is Int || this@case_5_2 == null)
return !(this@case_5_2 !is Int || <!SENSELESS_COMPARISON!>this@case_5_2 == null<!>)
}
fun <T : Number?> T.case_5_3(): Boolean? {
contract { returnsNotNull() implies (this@case_5_3 !is Int || this@case_5_3 == null) }
return if (this@case_5_3 !is Int || this@case_5_3 == null) true else null
return if (this@case_5_3 !is Int || <!SENSELESS_COMPARISON!>this@case_5_3 == null<!>) true else null
}
fun <T : Number?> T.case_5_4(): Boolean? {
contract { returns(null) implies (this@case_5_4 !is Int || this@case_5_4 == null) }
return if (this@case_5_4 !is Int || this@case_5_4 == null) null else true
return if (this@case_5_4 !is Int || <!SENSELESS_COMPARISON!>this@case_5_4 == null<!>) null else true
}
// TESTCASE NUMBER: 6
inline fun <reified T : Any?> T?.case_6_1(): Boolean {
contract { returns(true) implies (this@case_6_1 !is Number || this@case_6_1 !is Int || this@case_6_1 == null) }
return this@case_6_1 !is Number || this@case_6_1 !is Int || this@case_6_1 == null
return this@case_6_1 !is Number || this@case_6_1 !is Int || <!SENSELESS_COMPARISON!>this@case_6_1 == null<!>
}
inline fun <reified T : Any?> T?.case_6_2(): Boolean {
contract { returns(false) implies (this@case_6_2 !is Number || this@case_6_2 !is Int || this@case_6_2 == null) }
return !(this@case_6_2 !is Number || this@case_6_2 !is Int || this@case_6_2 == null)
return !(this@case_6_2 !is Number || this@case_6_2 !is Int || <!SENSELESS_COMPARISON!>this@case_6_2 == null<!>)
}
inline fun <reified T : Any?> T?.case_6_3(): Boolean? {
contract { returnsNotNull() implies (this@case_6_3 is Number && this@case_6_3 is Int && this@case_6_3 != null) }
return if (this@case_6_3 is Number && this@case_6_3 is Int && this@case_6_3 != null) true else null
return if (this@case_6_3 is Number && this@case_6_3 is Int && <!SENSELESS_COMPARISON!>this@case_6_3 != null<!>) true else null
}
inline fun <reified T : Any?> T?.case_6_4(): Boolean? {
contract { returns(null) implies (this@case_6_4 is Number && this@case_6_4 is Int && this@case_6_4 != null) }
return if (this@case_6_4 is Number && this@case_6_4 is Int && this@case_6_4 != null) null else true
return if (this@case_6_4 is Number && this@case_6_4 is Int && <!SENSELESS_COMPARISON!>this@case_6_4 != null<!>) null else true
}
// FILE: main.kt
@@ -15,13 +15,13 @@ fun <T> T?.case_1(value_1: Int?) {
// TESTCASE NUMBER: 2
fun <T : Number?> T.case_2(value_2: Any?) {
contract { returns() implies (this@case_2 !is Int || this@case_2 == null || value_2 !is Number || value_2 == null) }
if (!(this@case_2 !is Int || this@case_2 == null || value_2 !is Number || value_2 == null)) throw Exception()
if (!(this@case_2 !is Int || <!SENSELESS_COMPARISON!>this@case_2 == null<!> || value_2 !is Number || <!SENSELESS_COMPARISON!>value_2 == null<!>)) throw Exception()
}
// TESTCASE NUMBER: 3
fun <T : Any?> T?.case_3(value_2: Any?) {
contract { returns() implies (this@case_3 !is Number || this@case_3 !is Int || this@case_3 == null || value_2 == null) }
if (!(this@case_3 !is Number || this@case_3 !is Int || this@case_3 == null || value_2 == null)) throw Exception()
if (!(this@case_3 !is Number || this@case_3 !is Int || <!SENSELESS_COMPARISON!>this@case_3 == null<!> || value_2 == null)) throw Exception()
}
// TESTCASE NUMBER: 4
@@ -51,37 +51,37 @@ fun <T> T?.case_5_4(value_1: Int?): Boolean? {
// TESTCASE NUMBER: 6
fun <T : Number?> T.case_6_1(value_2: Any?): Boolean {
contract { returns(true) implies (this@case_6_1 !is Int || this@case_6_1 == null || value_2 !is Number || value_2 == null) }
return this@case_6_1 !is Int || this@case_6_1 == null || value_2 !is Number || value_2 == null
return this@case_6_1 !is Int || <!SENSELESS_COMPARISON!>this@case_6_1 == null<!> || value_2 !is Number || <!SENSELESS_COMPARISON!>value_2 == null<!>
}
fun <T : Number?> T.case_6_2(value_2: Any?): Boolean {
contract { returns(false) implies (this@case_6_2 !is Int || this@case_6_2 == null || value_2 !is Number || value_2 == null) }
return !(this@case_6_2 !is Int || this@case_6_2 == null || value_2 !is Number || value_2 == null)
return !(this@case_6_2 !is Int || <!SENSELESS_COMPARISON!>this@case_6_2 == null<!> || value_2 !is Number || <!SENSELESS_COMPARISON!>value_2 == null<!>)
}
fun <T : Number?> T.case_6_3(value_2: Any?): Boolean? {
contract { returnsNotNull() implies (this@case_6_3 !is Int || this@case_6_3 == null || value_2 !is Number || value_2 == null) }
return if (this@case_6_3 !is Int || this@case_6_3 == null || value_2 !is Number || value_2 == null) true else null
return if (this@case_6_3 !is Int || <!SENSELESS_COMPARISON!>this@case_6_3 == null<!> || value_2 !is Number || <!SENSELESS_COMPARISON!>value_2 == null<!>) true else null
}
fun <T : Number?> T.case_6_4(value_2: Any?): Boolean? {
contract { returns(null) implies (this@case_6_4 !is Int || this@case_6_4 == null || value_2 !is Number || value_2 == null) }
return if (this@case_6_4 !is Int || this@case_6_4 == null || value_2 !is Number || value_2 == null) null else true
return if (this@case_6_4 !is Int || <!SENSELESS_COMPARISON!>this@case_6_4 == null<!> || value_2 !is Number || <!SENSELESS_COMPARISON!>value_2 == null<!>) null else true
}
// TESTCASE NUMBER: 7
fun <T : Any?> T?.case_7_1(value_2: Any?): Boolean {
contract { returns(true) implies (this@case_7_1 !is Number || this@case_7_1 !is Int || this@case_7_1 == null || value_2 == null) }
return this@case_7_1 !is Number || this@case_7_1 !is Int || this@case_7_1 == null || value_2 == null
return this@case_7_1 !is Number || this@case_7_1 !is Int || <!SENSELESS_COMPARISON!>this@case_7_1 == null<!> || value_2 == null
}
fun <T : Any?> T?.case_7_2(value_2: Any?): Boolean {
contract { returns(false) implies (this@case_7_2 !is Number || this@case_7_2 !is Int || this@case_7_2 == null || value_2 == null) }
return !(this@case_7_2 !is Number || this@case_7_2 !is Int || this@case_7_2 == null || value_2 == null)
return !(this@case_7_2 !is Number || this@case_7_2 !is Int || <!SENSELESS_COMPARISON!>this@case_7_2 == null<!> || value_2 == null)
}
fun <T : Any?> T?.case_7_3(value_2: Any?): Boolean? {
contract { returnsNotNull() implies (this@case_7_3 !is Number || this@case_7_3 !is Int || this@case_7_3 == null || value_2 == null) }
return if (this@case_7_3 !is Number || this@case_7_3 !is Int || this@case_7_3 == null || value_2 == null) true else null
return if (this@case_7_3 !is Number || this@case_7_3 !is Int || <!SENSELESS_COMPARISON!>this@case_7_3 == null<!> || value_2 == null) true else null
}
fun <T : Any?> T?.case_7_4(value_2: Any?): Boolean? {
contract { returns(null) implies (this@case_7_4 !is Number || this@case_7_4 !is Int || this@case_7_4 == null || value_2 == null) }
return if (this@case_7_4 !is Number || this@case_7_4 !is Int || this@case_7_4 == null || value_2 == null) null else true
return if (this@case_7_4 !is Number || this@case_7_4 !is Int || <!SENSELESS_COMPARISON!>this@case_7_4 == null<!> || value_2 == null) null else true
}
// TESTCASE NUMBER: 8
@@ -25,7 +25,7 @@ fun case_4(value_1: Number, block: (() -> Unit)?): Boolean? {
returns(null) implies (block == null)
}<!>
return value_1 == null
return <!SENSELESS_COMPARISON!>value_1 == null<!>
}
// TESTCASE NUMBER: 5
@@ -48,7 +48,7 @@ fun <T> T?.case_6(value_1: Number, value_2: String?): Boolean? {
returnsNotNull() implies (value_2 == null)
}<!>
return value_1 == null
return <!SENSELESS_COMPARISON!>value_1 == null<!>
}
// FILE: main.kt
@@ -69,7 +69,7 @@ fun case_3(value_1: Int?) {
// TESTCASE NUMBER: 4
fun case_4(value_1: Any?) {
if (contracts.case_4(value_1) != null) {
if (<!SENSELESS_COMPARISON!>contracts.case_4(value_1) != null<!>) {
value_1.toByte()
}
}
@@ -15,13 +15,13 @@ fun <T> T?.case_1() {
// TESTCASE NUMBER: 2
fun <T : Number?> T.case_2() {
contract { returns() implies (this@case_2 is Int && this@case_2 != null) }
if (!(this@case_2 is Int && this@case_2 != null)) throw Exception()
if (!(this@case_2 is Int && <!SENSELESS_COMPARISON!>this@case_2 != null<!>)) throw Exception()
}
// TESTCASE NUMBER: 3
inline fun <reified T : Any?> T?.case_3() {
contract { returns() implies (this@case_3 is Number && this@case_3 is Int && this@case_3 != null) }
if (!(this@case_3 is Number && this@case_3 is Int && this@case_3 != null)) throw Exception()
if (!(this@case_3 is Number && this@case_3 is Int && <!SENSELESS_COMPARISON!>this@case_3 != null<!>)) throw Exception()
}
// TESTCASE NUMBER: 4
@@ -45,37 +45,37 @@ fun <T> T?.case_4_4(): Boolean? {
// TESTCASE NUMBER: 5
fun <T : Number?> T.case_5_1(): Boolean {
contract { returns(true) implies (this@case_5_1 is Int && this@case_5_1 != null) }
return this@case_5_1 is Int && this@case_5_1 != null
return this@case_5_1 is Int && <!SENSELESS_COMPARISON!>this@case_5_1 != null<!>
}
fun <T : Number?> T.case_5_2(): Boolean {
contract { returns(false) implies (this@case_5_2 is Int && this@case_5_2 != null) }
return !(this@case_5_2 is Int && this@case_5_2 != null)
return !(this@case_5_2 is Int && <!SENSELESS_COMPARISON!>this@case_5_2 != null<!>)
}
fun <T : Number?> T.case_5_3(): Boolean? {
contract { returnsNotNull() implies (this@case_5_3 is Int && this@case_5_3 != null) }
return if (this@case_5_3 is Int && this@case_5_3 != null) true else null
return if (this@case_5_3 is Int && <!SENSELESS_COMPARISON!>this@case_5_3 != null<!>) true else null
}
fun <T : Number?> T.case_5_4(): Boolean? {
contract { returns(null) implies (this@case_5_4 is Int && this@case_5_4 != null) }
return if (this@case_5_4 is Int && this@case_5_4 != null) null else true
return if (this@case_5_4 is Int && <!SENSELESS_COMPARISON!>this@case_5_4 != null<!>) null else true
}
// TESTCASE NUMBER: 6
inline fun <reified T : Any?> T?.case_6_1(): Boolean {
contract { returns(true) implies (this@case_6_1 is Number && this@case_6_1 is Int && this@case_6_1 != null) }
return this@case_6_1 is Number && this@case_6_1 is Int && this@case_6_1 != null
return this@case_6_1 is Number && this@case_6_1 is Int && <!SENSELESS_COMPARISON!>this@case_6_1 != null<!>
}
inline fun <reified T : Any?> T?.case_6_2(): Boolean {
contract { returns(false) implies (this@case_6_2 is Number && this@case_6_2 is Int && this@case_6_2 != null) }
return !(this@case_6_2 is Number && this@case_6_2 is Int && this@case_6_2 != null)
return !(this@case_6_2 is Number && this@case_6_2 is Int && <!SENSELESS_COMPARISON!>this@case_6_2 != null<!>)
}
inline fun <reified T : Any?> T?.case_6_3(): Boolean? {
contract { returnsNotNull() implies (this@case_6_3 is Number && this@case_6_3 is Int && this@case_6_3 != null) }
return if (this@case_6_3 is Number && this@case_6_3 is Int && this@case_6_3 != null) true else null
return if (this@case_6_3 is Number && this@case_6_3 is Int && <!SENSELESS_COMPARISON!>this@case_6_3 != null<!>) true else null
}
inline fun <reified T : Any?> T?.case_6_4(): Boolean? {
contract { returns(null) implies (this@case_6_4 is Number && this@case_6_4 is Int && this@case_6_4 != null) }
return if (this@case_6_4 is Number && this@case_6_4 is Int && this@case_6_4 != null) null else true
return if (this@case_6_4 is Number && this@case_6_4 is Int && <!SENSELESS_COMPARISON!>this@case_6_4 != null<!>) null else true
}
// FILE: main.kt
@@ -15,13 +15,13 @@ fun <T> T?.case_1(value_1: Int?) {
// TESTCASE NUMBER: 2
fun <T : Number?> T.case_2(value_2: Any?) {
contract { returns() implies (this@case_2 is Int && this@case_2 != null && value_2 is Number && value_2 != null) }
if (!(this@case_2 is Int && this@case_2 != null && value_2 is Number && value_2 != null)) throw Exception()
if (!(this@case_2 is Int && <!SENSELESS_COMPARISON!>this@case_2 != null<!> && value_2 is Number && <!SENSELESS_COMPARISON!>value_2 != null<!>)) throw Exception()
}
// TESTCASE NUMBER: 3
fun <T : Any?> T?.case_3(value_2: Any?) {
contract { returns() implies (this@case_3 is Number && this@case_3 is Int && this@case_3 != null && value_2 != null) }
if (!(this@case_3 is Number && this@case_3 is Int && this@case_3 != null && value_2 != null)) throw Exception()
if (!(this@case_3 is Number && this@case_3 is Int && <!SENSELESS_COMPARISON!>this@case_3 != null<!> && value_2 != null)) throw Exception()
}
// TESTCASE NUMBER: 4
@@ -51,37 +51,37 @@ fun <T> T?.case_5_4(value_1: Int?): Boolean? {
// TESTCASE NUMBER: 6
fun <T : Number?> T.case_6_1(value_2: Any?): Boolean {
contract { returns(true) implies (this@case_6_1 is Int && this@case_6_1 != null && value_2 is Number && value_2 != null) }
return this@case_6_1 is Int && this@case_6_1 != null && value_2 is Number && value_2 != null
return this@case_6_1 is Int && <!SENSELESS_COMPARISON!>this@case_6_1 != null<!> && value_2 is Number && <!SENSELESS_COMPARISON!>value_2 != null<!>
}
fun <T : Number?> T.case_6_2(value_2: Any?): Boolean {
contract { returns(false) implies (this@case_6_2 is Int && this@case_6_2 != null && value_2 is Number && value_2 != null) }
return !(this@case_6_2 is Int && this@case_6_2 != null && value_2 is Number && value_2 != null)
return !(this@case_6_2 is Int && <!SENSELESS_COMPARISON!>this@case_6_2 != null<!> && value_2 is Number && <!SENSELESS_COMPARISON!>value_2 != null<!>)
}
fun <T : Number?> T.case_6_3(value_2: Any?): Boolean? {
contract { returnsNotNull() implies (this@case_6_3 is Int && this@case_6_3 != null && value_2 is Number && value_2 != null) }
return if (this@case_6_3 is Int && this@case_6_3 != null && value_2 is Number && value_2 != null) true else null
return if (this@case_6_3 is Int && <!SENSELESS_COMPARISON!>this@case_6_3 != null<!> && value_2 is Number && <!SENSELESS_COMPARISON!>value_2 != null<!>) true else null
}
fun <T : Number?> T.case_6_4(value_2: Any?): Boolean? {
contract { returns(null) implies (this@case_6_4 is Int && this@case_6_4 != null && value_2 is Number && value_2 != null) }
return if (this@case_6_4 is Int && this@case_6_4 != null && value_2 is Number && value_2 != null) null else true
return if (this@case_6_4 is Int && <!SENSELESS_COMPARISON!>this@case_6_4 != null<!> && value_2 is Number && <!SENSELESS_COMPARISON!>value_2 != null<!>) null else true
}
// TESTCASE NUMBER: 7
fun <T : Any?> T?.case_7_1(value_2: Any?): Boolean {
contract { returns(true) implies (this@case_7_1 is Number && this@case_7_1 is Int && this@case_7_1 != null && value_2 != null) }
return this@case_7_1 is Number && this@case_7_1 is Int && this@case_7_1 != null && value_2 != null
return this@case_7_1 is Number && this@case_7_1 is Int && <!SENSELESS_COMPARISON!>this@case_7_1 != null<!> && value_2 != null
}
fun <T : Any?> T?.case_7_2(value_2: Any?): Boolean {
contract { returns(true) implies (this@case_7_2 is Number && this@case_7_2 is Int && this@case_7_2 != null && value_2 != null) }
return this@case_7_2 is Number && this@case_7_2 is Int && this@case_7_2 != null && value_2 != null
return this@case_7_2 is Number && this@case_7_2 is Int && <!SENSELESS_COMPARISON!>this@case_7_2 != null<!> && value_2 != null
}
fun <T : Any?> T?.case_7_3(value_2: Any?): Boolean? {
contract { returnsNotNull() implies (this@case_7_3 is Number && this@case_7_3 is Int && this@case_7_3 != null && value_2 != null) }
return if (this@case_7_3 is Number && this@case_7_3 is Int && this@case_7_3 != null && value_2 != null) true else null
return if (this@case_7_3 is Number && this@case_7_3 is Int && <!SENSELESS_COMPARISON!>this@case_7_3 != null<!> && value_2 != null) true else null
}
fun <T : Any?> T?.case_7_4(value_2: Any?): Boolean? {
contract { returns(null) implies (this@case_7_4 is Number && this@case_7_4 is Int && this@case_7_4 != null && value_2 != null) }
return if (this@case_7_4 is Number && this@case_7_4 is Int && this@case_7_4 != null && value_2 != null) null else true
return if (this@case_7_4 is Number && this@case_7_4 is Int && <!SENSELESS_COMPARISON!>this@case_7_4 != null<!> && value_2 != null) null else true
}
// TESTCASE NUMBER: 8
@@ -26,7 +26,7 @@ fun case_4(value_1: Number, block: (() -> Unit)?): Boolean? {
returns(null) implies (block != null)
}
return value_1 == null
return <!SENSELESS_COMPARISON!>value_1 == null<!>
}
// TESTCASE NUMBER: 5
@@ -49,7 +49,7 @@ fun <T> T?.case_6(value_1: Number, value_2: String?): Boolean? {
returnsNotNull() implies (value_2 != null)
}<!>
return value_1 == null
return <!SENSELESS_COMPARISON!>value_1 == null<!>
}
// FILE: main.kt