FIR: add equality call checker
Added checker for FirEqualityOperatorCall. It's surfaced as one of the following diagnostics depending on the PSI structure and types under comparison: * INCOMPATIBLE_TYPES(_WARNING) * EQUALITY_NOT_APPLICABLE(_WARNING) * INCOMPATIBLE_ENUM_COMPARISON_ERROR Comparing with FE1.0, the current implementation is more conservative and only highlights error if the types are known to follow certain contracts with `equals` method. Otherwise, the checker reports warnings instead. However, the current checker is more strict in the following situations: 1. it now rejects incompatible enum types like `Enum<E1>` and `Enum<E2>`, which was previously accepted 2. it now rejects incompatible class types like `Class<String>` and `Class<Int>`, which was previously accepted 3. the check now takes smart cast into consideration, so `if (x is String) x == 3` is now rejected
This commit is contained in:
committed by
teamcityserver
parent
787c743333
commit
7bb81ef157
@@ -14,10 +14,10 @@ fun f(): Unit {
|
||||
x == 1
|
||||
x != 1
|
||||
|
||||
A() == 1
|
||||
<!EQUALITY_NOT_APPLICABLE!>A() == 1<!>
|
||||
|
||||
x === "1"
|
||||
x !== "1"
|
||||
<!EQUALITY_NOT_APPLICABLE!>x === "1"<!>
|
||||
<!EQUALITY_NOT_APPLICABLE!>x !== "1"<!>
|
||||
|
||||
x === 1
|
||||
x !== 1
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ val test_dd = d === d || d !== d
|
||||
val test_cc = c === c || c !== c
|
||||
|
||||
// Identity for primitive values of different types (no extra error)
|
||||
val test_zb = z === b || z !== b
|
||||
val test_zb = <!EQUALITY_NOT_APPLICABLE!>z === b<!> || <!EQUALITY_NOT_APPLICABLE!>z !== b<!>
|
||||
|
||||
// Primitive vs nullable
|
||||
val test_znz = z === nz || nz === z || z !== nz || nz !== z
|
||||
|
||||
@@ -5,7 +5,7 @@ import kotlin.reflect.KClass
|
||||
class Foo {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other === null || other::class != this::class) return false
|
||||
if (other === null || <!EQUALITY_NOT_APPLICABLE!>other::class != this::class<!>) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
//KT-1185 Support full enumeration check for 'when'
|
||||
|
||||
package kt1185
|
||||
|
||||
enum class Direction {
|
||||
NORTH,
|
||||
SOUTH,
|
||||
WEST,
|
||||
EAST
|
||||
}
|
||||
|
||||
class A {
|
||||
companion object {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
enum class Color(val rgb : Int) {
|
||||
RED(0xFF0000),
|
||||
GREEN(0x00FF00),
|
||||
BLUE(0x0000FF)
|
||||
}
|
||||
|
||||
fun foo(d: Direction) = when(d) { //no 'else' should be requested
|
||||
Direction.NORTH -> 1
|
||||
Direction.SOUTH -> 2
|
||||
A -> 1
|
||||
Direction.WEST -> 3
|
||||
Direction.EAST -> 4
|
||||
}
|
||||
|
||||
fun foo1(d: Direction) = <!NO_ELSE_IN_WHEN!>when<!>(d) {
|
||||
Direction.NORTH -> 1
|
||||
Direction.SOUTH -> 2
|
||||
Direction.WEST -> 3
|
||||
}
|
||||
|
||||
fun bar(c: Color) = when (c) {
|
||||
Color.RED -> 1
|
||||
Color.GREEN -> 2
|
||||
Color.BLUE -> 3
|
||||
}
|
||||
|
||||
fun bar1(c: Color) = <!NO_ELSE_IN_WHEN!>when<!> (c) {
|
||||
Color.RED -> 1
|
||||
Color.GREEN -> 2
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
//KT-1185 Support full enumeration check for 'when'
|
||||
|
||||
package kt1185
|
||||
@@ -44,4 +45,4 @@ fun bar(c: Color) = when (c) {
|
||||
fun bar1(c: Color) = <!NO_ELSE_IN_WHEN!>when<!> (c) {
|
||||
Color.RED -> 1
|
||||
Color.GREEN -> 2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,6 @@ public enum JavaEnumB {}
|
||||
enum class KotlinEnumA
|
||||
enum class KotlinEnumB
|
||||
|
||||
fun jj(a: JavaEnumA, b: JavaEnumB) = a == b
|
||||
fun jk(a: JavaEnumA, b: KotlinEnumB) = a == b
|
||||
fun kk(a: KotlinEnumA, b: KotlinEnumB) = a == b
|
||||
fun jj(a: JavaEnumA, b: JavaEnumB) = <!EQUALITY_NOT_APPLICABLE_WARNING!>a == b<!>
|
||||
fun jk(a: JavaEnumA, b: KotlinEnumB) = <!EQUALITY_NOT_APPLICABLE_WARNING!>a == b<!>
|
||||
fun kk(a: KotlinEnumA, b: KotlinEnumB) = <!EQUALITY_NOT_APPLICABLE_WARNING!>a == b<!>
|
||||
|
||||
@@ -32,8 +32,8 @@ fun useEn2(x: En2) = x
|
||||
fun bar(x: Any) {
|
||||
if (x is En && x is En2) {
|
||||
when (x) {
|
||||
En.A -> useEn(x)
|
||||
En2.D -> useEn2(x)
|
||||
<!INCOMPATIBLE_TYPES!>En.A<!> -> useEn(x)
|
||||
<!INCOMPATIBLE_TYPES!>En2.D<!> -> useEn2(x)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
+15
-15
@@ -7,15 +7,15 @@ interface I {
|
||||
enum class E1 : I {
|
||||
A {
|
||||
override fun foo() {
|
||||
this == E2.A
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>this == E2.A<!>
|
||||
|
||||
val q = this
|
||||
when (q) {
|
||||
this -> {}
|
||||
E1.A -> {}
|
||||
E1.B -> {}
|
||||
E2.A -> {}
|
||||
E2.B -> {}
|
||||
<!INCOMPATIBLE_TYPES_WARNING!>E2.A<!> -> {}
|
||||
<!INCOMPATIBLE_TYPES_WARNING!>E2.B<!> -> {}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
@@ -41,13 +41,13 @@ enum class E2 : I {
|
||||
}
|
||||
|
||||
fun foo1(e1: E1, e2: E2) {
|
||||
e1 == e2
|
||||
e1 != e2
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == e2<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 != e2<!>
|
||||
|
||||
e1 == E2.A
|
||||
E1.B == e2
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == E2.A<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>E1.B == e2<!>
|
||||
|
||||
E1.A == E2.B
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>E1.A == E2.B<!>
|
||||
|
||||
e1 == E1.A
|
||||
E1.A == e1
|
||||
@@ -58,27 +58,27 @@ fun foo1(e1: E1, e2: E2) {
|
||||
fun foo2(e1: E1, e2: E2) {
|
||||
when (e1) {
|
||||
E1.A -> {}
|
||||
E2.A -> {}
|
||||
E2.B -> {}
|
||||
<!INCOMPATIBLE_TYPES_WARNING!>E2.A<!> -> {}
|
||||
<!INCOMPATIBLE_TYPES_WARNING!>E2.B<!> -> {}
|
||||
e1 -> {}
|
||||
e2 -> {}
|
||||
<!INCOMPATIBLE_TYPES_WARNING!>e2<!> -> {}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
fun foo3(e1: Enum<E1>, e2: Enum<E2>, e: Enum<*>) {
|
||||
e1 == e
|
||||
e1 == e2
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == e2<!>
|
||||
|
||||
e1 == E1.A
|
||||
e1 == E2.A
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == E2.A<!>
|
||||
|
||||
when (e1) {
|
||||
e1 -> {}
|
||||
e2 -> {}
|
||||
<!INCOMPATIBLE_TYPES_WARNING!>e2<!> -> {}
|
||||
e -> {}
|
||||
E1.A -> {}
|
||||
E2.A -> {}
|
||||
<!INCOMPATIBLE_TYPES_WARNING!>E2.A<!> -> {}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,13 +9,13 @@ enum class E2 {
|
||||
}
|
||||
|
||||
fun foo1(e1: E1, e2: E2) {
|
||||
e1 == e2
|
||||
e1 != e2
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == e2<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 != e2<!>
|
||||
|
||||
e1 == E2.A
|
||||
E1.B == e2
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == E2.A<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>E1.B == e2<!>
|
||||
|
||||
E1.A == E2.B
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>E1.A == E2.B<!>
|
||||
|
||||
e1 == E1.A
|
||||
E1.A == e1
|
||||
@@ -26,27 +26,27 @@ fun foo1(e1: E1, e2: E2) {
|
||||
fun foo2(e1: E1, e2: E2) {
|
||||
when (e1) {
|
||||
E1.A -> {}
|
||||
E2.A -> {}
|
||||
E2.B -> {}
|
||||
<!INCOMPATIBLE_TYPES_WARNING!>E2.A<!> -> {}
|
||||
<!INCOMPATIBLE_TYPES_WARNING!>E2.B<!> -> {}
|
||||
e1 -> {}
|
||||
e2 -> {}
|
||||
<!INCOMPATIBLE_TYPES_WARNING!>e2<!> -> {}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
fun foo3(e1: Enum<E1>, e2: Enum<E2>, e: Enum<*>) {
|
||||
e1 == e
|
||||
e1 == e2
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == e2<!>
|
||||
|
||||
e1 == E1.A
|
||||
e1 == E2.A
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == E2.A<!>
|
||||
|
||||
when (e1) {
|
||||
e1 -> {}
|
||||
e2 -> {}
|
||||
<!INCOMPATIBLE_TYPES_WARNING!>e2<!> -> {}
|
||||
e -> {}
|
||||
E1.A -> {}
|
||||
E2.A -> {}
|
||||
<!INCOMPATIBLE_TYPES_WARNING!>E2.A<!> -> {}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
@@ -63,15 +63,15 @@ interface MyInterface
|
||||
open class MyOpenClass
|
||||
|
||||
fun foo4(e1: E1, i: MyInterface, c: MyOpenClass) {
|
||||
e1 == i
|
||||
i == e1
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == i<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>i == e1<!>
|
||||
|
||||
e1 == c
|
||||
c == e1
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == c<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>c == e1<!>
|
||||
|
||||
when (e1) {
|
||||
i -> {}
|
||||
c -> {}
|
||||
<!INCOMPATIBLE_TYPES_WARNING!>i<!> -> {}
|
||||
<!INCOMPATIBLE_TYPES_WARNING!>c<!> -> {}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
@@ -90,10 +90,10 @@ fun foo6(e1: E1?, e2: E2) {
|
||||
e1 == null
|
||||
null == e1
|
||||
|
||||
e1 == E2.A
|
||||
E2.A == e1
|
||||
e1 == e2
|
||||
e2 == e1
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == E2.A<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>E2.A == e1<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == e2<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e2 == e1<!>
|
||||
|
||||
e2 == null
|
||||
null == e2
|
||||
@@ -117,16 +117,16 @@ fun <T> foo8(e1: E1?, e2: E2, t: T) {
|
||||
}
|
||||
|
||||
fun <T, K> foo9(e1: E1?, e2: E2, t: T, k: K) where T : MyInterface, T : MyOpenClass, K : MyInterface {
|
||||
e1 == t
|
||||
t == e1
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == t<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>t == e1<!>
|
||||
|
||||
e2 == t
|
||||
t == e2
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e2 == t<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>t == e2<!>
|
||||
|
||||
E1.A == t
|
||||
t == E1.A
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>E1.A == t<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>t == E1.A<!>
|
||||
|
||||
E3.X == t
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>E3.X == t<!>
|
||||
|
||||
E3.X == k
|
||||
k == E3.X
|
||||
@@ -137,9 +137,9 @@ interface Inv<T>
|
||||
enum class E4 : Inv<Int> { A }
|
||||
|
||||
fun foo10(e4: E4, invString: Inv<String>) {
|
||||
e4 == invString
|
||||
invString == e4
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e4 == invString<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>invString == e4<!>
|
||||
|
||||
E4.A == invString
|
||||
invString == E4.A
|
||||
}
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>E4.A == invString<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>invString == E4.A<!>
|
||||
}
|
||||
|
||||
@@ -9,13 +9,13 @@ enum class E2 {
|
||||
}
|
||||
|
||||
fun foo1(e1: E1, e2: E2) {
|
||||
e1 == e2
|
||||
e1 != e2
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == e2<!>
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 != e2<!>
|
||||
|
||||
e1 == E2.A
|
||||
E1.B == e2
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == E2.A<!>
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>E1.B == e2<!>
|
||||
|
||||
E1.A == E2.B
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>E1.A == E2.B<!>
|
||||
|
||||
e1 == E1.A
|
||||
E1.A == e1
|
||||
@@ -26,27 +26,27 @@ fun foo1(e1: E1, e2: E2) {
|
||||
fun foo2(e1: E1, e2: E2) {
|
||||
when (e1) {
|
||||
E1.A -> {}
|
||||
E2.A -> {}
|
||||
E2.B -> {}
|
||||
<!INCOMPATIBLE_TYPES!>E2.A<!> -> {}
|
||||
<!INCOMPATIBLE_TYPES!>E2.B<!> -> {}
|
||||
e1 -> {}
|
||||
e2 -> {}
|
||||
<!INCOMPATIBLE_TYPES!>e2<!> -> {}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
fun foo3(e1: Enum<E1>, e2: Enum<E2>, e: Enum<*>) {
|
||||
e1 == e
|
||||
e1 == e2
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == e2<!>
|
||||
|
||||
e1 == E1.A
|
||||
e1 == E2.A
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == E2.A<!>
|
||||
|
||||
when (e1) {
|
||||
e1 -> {}
|
||||
e2 -> {}
|
||||
<!INCOMPATIBLE_TYPES!>e2<!> -> {}
|
||||
e -> {}
|
||||
E1.A -> {}
|
||||
E2.A -> {}
|
||||
<!INCOMPATIBLE_TYPES!>E2.A<!> -> {}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
@@ -63,15 +63,15 @@ interface MyInterface
|
||||
open class MyOpenClass
|
||||
|
||||
fun foo4(e1: E1, i: MyInterface, c: MyOpenClass) {
|
||||
e1 == i
|
||||
i == e1
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == i<!>
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>i == e1<!>
|
||||
|
||||
e1 == c
|
||||
c == e1
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == c<!>
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>c == e1<!>
|
||||
|
||||
when (e1) {
|
||||
i -> {}
|
||||
c -> {}
|
||||
<!INCOMPATIBLE_TYPES!>i<!> -> {}
|
||||
<!INCOMPATIBLE_TYPES!>c<!> -> {}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
@@ -90,10 +90,10 @@ fun foo6(e1: E1?, e2: E2) {
|
||||
e1 == null
|
||||
null == e1
|
||||
|
||||
e1 == E2.A
|
||||
E2.A == e1
|
||||
e1 == e2
|
||||
e2 == e1
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == E2.A<!>
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>E2.A == e1<!>
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == e2<!>
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e2 == e1<!>
|
||||
|
||||
e2 == null
|
||||
null == e2
|
||||
@@ -117,16 +117,16 @@ fun <T> foo8(e1: E1?, e2: E2, t: T) {
|
||||
}
|
||||
|
||||
fun <T, K> foo9(e1: E1?, e2: E2, t: T, k: K) where T : MyInterface, T : MyOpenClass, K : MyInterface {
|
||||
e1 == t
|
||||
t == e1
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == t<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>t == e1<!>
|
||||
|
||||
e2 == t
|
||||
t == e2
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e2 == t<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>t == e2<!>
|
||||
|
||||
E1.A == t
|
||||
t == E1.A
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>E1.A == t<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>t == E1.A<!>
|
||||
|
||||
E3.X == t
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>E3.X == t<!>
|
||||
|
||||
E3.X == k
|
||||
k == E3.X
|
||||
@@ -137,9 +137,9 @@ interface Inv<T>
|
||||
enum class E4 : Inv<Int> { A }
|
||||
|
||||
fun foo10(e4: E4, invString: Inv<String>) {
|
||||
e4 == invString
|
||||
invString == e4
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>e4 == invString<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>invString == e4<!>
|
||||
|
||||
E4.A == invString
|
||||
invString == E4.A
|
||||
}
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>E4.A == invString<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>invString == E4.A<!>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
class A<T>
|
||||
class AIn<in T>
|
||||
class AOut<out T>
|
||||
class A2
|
||||
|
||||
open class B<T>
|
||||
open class BIn<in T>
|
||||
open class BOut<out T>
|
||||
|
||||
open class C
|
||||
open class D
|
||||
|
||||
enum class E
|
||||
interface I
|
||||
|
||||
interface T<T>
|
||||
|
||||
open class TSub1 : T<String>
|
||||
open class TSub2 : T<Int>
|
||||
|
||||
fun foo(
|
||||
string: String, int: Int,
|
||||
strings: List<String>, ints: List<Int>,
|
||||
|
||||
aString: A<String>, aInt: A<Int>,
|
||||
aOutString: A<out String>, aOutInt: A<out Int>,
|
||||
aOutString2: AOut<String>, aOutInt2: AOut<Int>,
|
||||
aInString: A<in String>, aInInt: A<in Int>,
|
||||
aInString2: AIn<String>, aInInt2: AIn<Int>,
|
||||
|
||||
bString: B<String>, bInt: B<Int>,
|
||||
bOutString: B<out String>, bOutInt: B<out Int>,
|
||||
bOutString2: BOut<String>, bOutInt2: BOut<Int>,
|
||||
bInString: B<in String>, bInInt: B<in Int>,
|
||||
bInString2: BIn<String>, bInInt2: BIn<Int>,
|
||||
|
||||
a2: A2,
|
||||
|
||||
e: E,
|
||||
i: I,
|
||||
|
||||
ac: A<C>, ad: A<D>,
|
||||
|
||||
tSub1: TSub1,
|
||||
tSub2: TSub2,
|
||||
|
||||
aListInt: A<List<Int>>,
|
||||
aSetInt: A<Set<Int>>,
|
||||
aListString: A<List<String>>,
|
||||
) {
|
||||
"a" == "b"
|
||||
1 == 2
|
||||
<!EQUALITY_NOT_APPLICABLE!>"" == 2<!>
|
||||
|
||||
<!EQUALITY_NOT_APPLICABLE!>string == int<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>strings == ints<!>
|
||||
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>aString == aInt<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>aOutString == aOutInt<!>
|
||||
aInString == aInInt
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>aOutString == aInInt<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>aInString == aOutInt<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>aOutString == aInt<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>aInString == aInt<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>aOutString2 == aOutInt2<!>
|
||||
aInString2 == aInInt2
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>aOutString2 == aInInt2<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>aInString2 == aOutInt2<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>aString == a2<!>
|
||||
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>bString == bInt<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>bOutString == bOutInt<!>
|
||||
bInString == bInInt
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>bOutString == bInInt<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>bInString == bOutInt<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>bOutString == bInt<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>bInString == bInt<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>bOutString2 == bOutInt2<!>
|
||||
bInString2 == bInInt2
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>bOutString2 == bInInt2<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>bInString2 == bOutInt2<!>
|
||||
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e == i<!>
|
||||
<!EQUALITY_NOT_APPLICABLE!>"" == i<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>ac == ad<!>
|
||||
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>tSub1 == tSub2<!>
|
||||
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>aString == bString<!>
|
||||
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>aListInt == aSetInt<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>aSetInt == aListString<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>aListString == aListInt<!>
|
||||
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>aString == aListString<!>
|
||||
<!EQUALITY_NOT_APPLICABLE_WARNING!>bString == aListString<!>
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
class A<T>
|
||||
class AIn<in T>
|
||||
class AOut<out T>
|
||||
class A2
|
||||
|
||||
open class B<T>
|
||||
open class BIn<in T>
|
||||
open class BOut<out T>
|
||||
|
||||
open class C
|
||||
open class D
|
||||
|
||||
enum class E
|
||||
interface I
|
||||
|
||||
interface T<T>
|
||||
|
||||
open class TSub1 : T<String>
|
||||
open class TSub2 : T<Int>
|
||||
|
||||
fun foo(
|
||||
string: String, int: Int,
|
||||
strings: List<String>, ints: List<Int>,
|
||||
|
||||
aString: A<String>, aInt: A<Int>,
|
||||
aOutString: A<out String>, aOutInt: A<out Int>,
|
||||
aOutString2: AOut<String>, aOutInt2: AOut<Int>,
|
||||
aInString: A<in String>, aInInt: A<in Int>,
|
||||
aInString2: AIn<String>, aInInt2: AIn<Int>,
|
||||
|
||||
bString: B<String>, bInt: B<Int>,
|
||||
bOutString: B<out String>, bOutInt: B<out Int>,
|
||||
bOutString2: BOut<String>, bOutInt2: BOut<Int>,
|
||||
bInString: B<in String>, bInInt: B<in Int>,
|
||||
bInString2: BIn<String>, bInInt2: BIn<Int>,
|
||||
|
||||
a2: A2,
|
||||
|
||||
e: E,
|
||||
i: I,
|
||||
|
||||
ac: A<C>, ad: A<D>,
|
||||
|
||||
tSub1: TSub1,
|
||||
tSub2: TSub2,
|
||||
|
||||
aListInt: A<List<Int>>,
|
||||
aSetInt: A<Set<Int>>,
|
||||
aListString: A<List<String>>,
|
||||
) {
|
||||
"a" == "b"
|
||||
1 == 2
|
||||
<!EQUALITY_NOT_APPLICABLE!>"" == 2<!>
|
||||
|
||||
<!EQUALITY_NOT_APPLICABLE!>string == int<!>
|
||||
strings == ints
|
||||
|
||||
aString == aInt
|
||||
<!EQUALITY_NOT_APPLICABLE!>aOutString == aOutInt<!>
|
||||
aInString == aInInt
|
||||
<!EQUALITY_NOT_APPLICABLE!>aOutString == aInInt<!>
|
||||
<!EQUALITY_NOT_APPLICABLE!>aInString == aOutInt<!>
|
||||
<!EQUALITY_NOT_APPLICABLE!>aOutString == aInt<!>
|
||||
aInString == aInt
|
||||
<!EQUALITY_NOT_APPLICABLE!>aOutString2 == aOutInt2<!>
|
||||
aInString2 == aInInt2
|
||||
<!EQUALITY_NOT_APPLICABLE!>aOutString2 == aInInt2<!>
|
||||
<!EQUALITY_NOT_APPLICABLE!>aInString2 == aOutInt2<!>
|
||||
<!EQUALITY_NOT_APPLICABLE!>aString == a2<!>
|
||||
|
||||
bString == bInt
|
||||
bOutString == bOutInt
|
||||
bInString == bInInt
|
||||
bOutString == bInInt
|
||||
bInString == bOutInt
|
||||
bOutString == bInt
|
||||
bInString == bInt
|
||||
bOutString2 == bOutInt2
|
||||
bInString2 == bInInt2
|
||||
bOutString2 == bInInt2
|
||||
bInString2 == bOutInt2
|
||||
|
||||
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e == i<!>
|
||||
<!EQUALITY_NOT_APPLICABLE!>"" == i<!>
|
||||
ac == ad
|
||||
|
||||
tSub1 == tSub2
|
||||
|
||||
aString == bString
|
||||
|
||||
aListInt == aSetInt
|
||||
aSetInt == aListString
|
||||
aListString == aListInt
|
||||
|
||||
aString == aListString
|
||||
bString == aListString
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package
|
||||
|
||||
public fun foo(/*0*/ string: kotlin.String, /*1*/ int: kotlin.Int, /*2*/ strings: kotlin.collections.List<kotlin.String>, /*3*/ ints: kotlin.collections.List<kotlin.Int>, /*4*/ aString: A<kotlin.String>, /*5*/ aInt: A<kotlin.Int>, /*6*/ aOutString: A<out kotlin.String>, /*7*/ aOutInt: A<out kotlin.Int>, /*8*/ aOutString2: AOut<kotlin.String>, /*9*/ aOutInt2: AOut<kotlin.Int>, /*10*/ aInString: A<in kotlin.String>, /*11*/ aInInt: A<in kotlin.Int>, /*12*/ aInString2: AIn<kotlin.String>, /*13*/ aInInt2: AIn<kotlin.Int>, /*14*/ bString: B<kotlin.String>, /*15*/ bInt: B<kotlin.Int>, /*16*/ bOutString: B<out kotlin.String>, /*17*/ bOutInt: B<out kotlin.Int>, /*18*/ bOutString2: BOut<kotlin.String>, /*19*/ bOutInt2: BOut<kotlin.Int>, /*20*/ bInString: B<in kotlin.String>, /*21*/ bInInt: B<in kotlin.Int>, /*22*/ bInString2: BIn<kotlin.String>, /*23*/ bInInt2: BIn<kotlin.Int>, /*24*/ a2: A2, /*25*/ e: E, /*26*/ i: I, /*27*/ ac: A<C>, /*28*/ ad: A<D>, /*29*/ tSub1: TSub1, /*30*/ tSub2: TSub2, /*31*/ aListInt: A<kotlin.collections.List<kotlin.Int>>, /*32*/ aSetInt: A<kotlin.collections.Set<kotlin.Int>>, /*33*/ aListString: A<kotlin.collections.List<kotlin.String>>, /*34*/ mutableListAny: kotlin.collections.MutableList<kotlin.Any>, /*35*/ listString: kotlin.collections.List<kotlin.String>): kotlin.Unit
|
||||
|
||||
public final class A</*0*/ T> {
|
||||
public constructor A</*0*/ T>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class A2 {
|
||||
public constructor A2()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class AIn</*0*/ in T> {
|
||||
public constructor AIn</*0*/ in T>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class AOut</*0*/ out T> {
|
||||
public constructor AOut</*0*/ out T>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public open class B</*0*/ T> {
|
||||
public constructor B</*0*/ T>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public open class BIn</*0*/ in T> {
|
||||
public constructor BIn</*0*/ in T>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public open class BOut</*0*/ out T> {
|
||||
public constructor BOut</*0*/ out T>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public open class C {
|
||||
public constructor C()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public open class D {
|
||||
public constructor D()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final enum class E : kotlin.Enum<E> {
|
||||
private constructor E()
|
||||
public final override /*1*/ /*fake_override*/ val name: kotlin.String
|
||||
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
|
||||
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
|
||||
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: E): kotlin.Int
|
||||
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
|
||||
public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<E!>!
|
||||
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
// Static members
|
||||
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): E
|
||||
public final /*synthesized*/ fun values(): kotlin.Array<E>
|
||||
}
|
||||
|
||||
public interface I {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface T</*0*/ T> {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public open class TSub1 : T<kotlin.String> {
|
||||
public constructor TSub1()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public open class TSub2 : T<kotlin.Int> {
|
||||
public constructor TSub2()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
Vendored
+3
-3
@@ -7,11 +7,11 @@ inline class Bar(val y: String)
|
||||
fun test(f1: Foo, f2: Foo, b1: Bar, fn1: Foo?, fn2: Foo?) {
|
||||
val a1 = f1 === f2 || f1 !== f2
|
||||
val a2 = f1 === f1
|
||||
val a3 = f1 === b1 || f1 !== b1
|
||||
val a3 = <!EQUALITY_NOT_APPLICABLE!>f1 === b1<!> || <!EQUALITY_NOT_APPLICABLE!>f1 !== b1<!>
|
||||
|
||||
val c1 = fn1 === fn2 || fn1 !== fn2
|
||||
val c2 = f1 === fn1 || f1 !== fn1
|
||||
val c3 = b1 === fn1 || b1 !== fn1
|
||||
val c3 = <!EQUALITY_NOT_APPLICABLE!>b1 === fn1<!> || <!EQUALITY_NOT_APPLICABLE!>b1 !== fn1<!>
|
||||
|
||||
val any = Any()
|
||||
|
||||
@@ -19,4 +19,4 @@ fun test(f1: Foo, f2: Foo, b1: Bar, fn1: Foo?, fn2: Foo?) {
|
||||
val d2 = f1 === any || f1 !== any
|
||||
val d3 = any === fn1 || any !== fn1
|
||||
val d4 = fn1 === any || fn1 !== any
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import checkSubtype
|
||||
fun main(args : Array<String>) {
|
||||
val x = checkSubtype<Any>(args[0])
|
||||
if(x is java.lang.CharSequence) {
|
||||
if ("a" == x) x.<!UNRESOLVED_REFERENCE!>length<!> else x.length() // OK
|
||||
if ("a" == x || "b" == x) x.<!UNRESOLVED_REFERENCE!>length<!> else x.length() // <– THEN ERROR
|
||||
if ("a" == x && "a" == x) x.<!UNRESOLVED_REFERENCE!>length<!> else x.length() // <– ELSE ERROR
|
||||
if (<!EQUALITY_NOT_APPLICABLE!>"a" == x<!>) x.<!UNRESOLVED_REFERENCE!>length<!> else x.length() // OK
|
||||
if (<!EQUALITY_NOT_APPLICABLE!>"a" == x<!> || <!EQUALITY_NOT_APPLICABLE!>"b" == x<!>) x.<!UNRESOLVED_REFERENCE!>length<!> else x.length() // <– THEN ERROR
|
||||
if (<!EQUALITY_NOT_APPLICABLE!>"a" == x<!> && <!EQUALITY_NOT_APPLICABLE!>"a" == x<!>) x.<!UNRESOLVED_REFERENCE!>length<!> else x.length() // <– ELSE ERROR
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ sealed class Tree {
|
||||
|
||||
fun maxIsClass(): Int = <!NO_ELSE_IN_WHEN!>when<!>(this) {
|
||||
Empty -> -1
|
||||
<!NO_COMPANION_OBJECT!>Leaf<!> -> 0
|
||||
<!INCOMPATIBLE_TYPES, NO_COMPANION_OBJECT!>Leaf<!> -> 0
|
||||
is Node -> this.left.max()
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ fun test(
|
||||
val ui = ui1 === ui2 || ui1 !== ui2
|
||||
val ul = ul1 === ul2 || ul1 !== ul2
|
||||
|
||||
val u = ub1 === ul1
|
||||
val u = <!EQUALITY_NOT_APPLICABLE!>ub1 === ul1<!>
|
||||
|
||||
val a1 = 1u === 2u || 1u !== 2u
|
||||
val a2 = 0xFFFF_FFFF_FFFF_FFFFu === 0xFFFF_FFFF_FFFF_FFFFu
|
||||
@@ -20,4 +20,4 @@ fun test(
|
||||
val bu2 = 1u
|
||||
|
||||
val c1 = bu1 === bu2 || bu1 !== bu2
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -14,11 +14,11 @@ value class Bar(val y: String)
|
||||
fun test(f1: Foo, f2: Foo, b1: Bar, fn1: Foo?, fn2: Foo?) {
|
||||
val a1 = f1 === f2 || f1 !== f2
|
||||
val a2 = f1 === f1
|
||||
val a3 = f1 === b1 || f1 !== b1
|
||||
val a3 = <!EQUALITY_NOT_APPLICABLE_WARNING!>f1 === b1<!> || <!EQUALITY_NOT_APPLICABLE_WARNING!>f1 !== b1<!>
|
||||
|
||||
val c1 = fn1 === fn2 || fn1 !== fn2
|
||||
val c2 = f1 === fn1 || f1 !== fn1
|
||||
val c3 = b1 === fn1 || b1 !== fn1
|
||||
val c3 = <!EQUALITY_NOT_APPLICABLE_WARNING!>b1 === fn1<!> || <!EQUALITY_NOT_APPLICABLE_WARNING!>b1 !== fn1<!>
|
||||
|
||||
val any = Any()
|
||||
|
||||
|
||||
+3
-3
@@ -23,7 +23,7 @@ fun foo() : Int {
|
||||
<!USELESS_IS_CHECK!>!is Int<!> -> 1
|
||||
<!USELESS_IS_CHECK!>is Any?<!> -> 1
|
||||
<!USELESS_IS_CHECK!>is Any<!> -> 1
|
||||
s -> 1
|
||||
<!INCOMPATIBLE_TYPES!>s<!> -> 1
|
||||
1 -> 1
|
||||
1 <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>a<!> -> 1
|
||||
in 1..<!UNRESOLVED_REFERENCE!>a<!> -> 1
|
||||
@@ -41,8 +41,8 @@ fun test() {
|
||||
val s = "";
|
||||
|
||||
when (x) {
|
||||
s -> 1
|
||||
"" -> 1
|
||||
<!INCOMPATIBLE_TYPES!>s<!> -> 1
|
||||
<!INCOMPATIBLE_TYPES!>""<!> -> 1
|
||||
x -> 1
|
||||
1 -> 1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user