[FIR] Fix K2 behavior according to RULES1

The compiler should only report diagnostics for
comparisons over builtins and identity-less types,
other incompatibilities should be reported
via inspections.

It's ok that in `equalityChecksOnIntegerTypes`
instead of `EQUALITY_NOT_APPLICABLE_WARNING` we get
`EQUALITY_NOT_APPLICABLE`, because
`ProperEqualityChecksInBuilderInferenceCalls`
is already active by default.

This change also replaces the notion of a representative superclass
with the least upper bound.
This makes complex types like
intersection/flexible transparent to
RULES1-based compatibility checks.
One way to look at it is to think
that this is an automatic way of handling
type parameters: automatic picking of
"interesting" bounds, and checking them against one another.

Note that `TypeIntersector.intersectTypes`
for `Int` and `T` where `T` is a type parameter
may return both `{Int & T}` or `null`
depending on `T`-s bounds. At the same time,
for type parameters `T` and `K` it will
always return `{T & K}`.

`ConeTypeIntersector.intersectTypes`, on the
other hand, will always return `{Int & T}`
irrespectively of the bounds. Meaning, the two
intersectors differ in corner cases.

`lowerBoundIfFlexible` call in `isLiterallyTypeParameter` is backed by
the `equalityOfFlexibleTypeParameters` test.

^KT-35134 #fixed-in-k2
^KT-22499 #fixed-in-k2
^KT-46383 #fixed-in-k2
This commit is contained in:
Nikolay Lunyak
2023-02-01 18:21:53 +02:00
committed by Space Team
parent 06e687addd
commit f0720c1d12
86 changed files with 1982 additions and 594 deletions
@@ -10,16 +10,16 @@ fun f(): Unit {
x <!UNSAFE_OPERATOR_CALL!><<!> 1
<!ASSIGNMENT_TYPE_MISMATCH!>x += 1<!>
x == 1
x != 1
<!EQUALITY_NOT_APPLICABLE_WARNING!>x == 1<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>x != 1<!>
<!EQUALITY_NOT_APPLICABLE!>A() == 1<!>
x === "1"
x !== "1"
<!EQUALITY_NOT_APPLICABLE!>x === "1"<!>
<!EQUALITY_NOT_APPLICABLE!>x !== "1"<!>
x === 1
x !== 1
<!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>x === 1<!>
<!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>x !== 1<!>
x..2
x in 1..2
@@ -22,60 +22,60 @@ val a: Any = 0
val na: Any? = 0
// Identity for primitive values of same type
val test_zz = z === z || z !== z
val test_bb = b === b || b !== b
val test_ss = s === s || s !== s
val test_ii = i === i || i !== i
val test_jj = j === j || j !== j
val test_ff = f === f || f !== f
val test_dd = d === d || d !== d
val test_cc = c === c || c !== c
val test_zz = <!DEPRECATED_IDENTITY_EQUALS!>z === z<!> || <!DEPRECATED_IDENTITY_EQUALS!>z !== z<!>
val test_bb = <!DEPRECATED_IDENTITY_EQUALS!>b === b<!> || <!DEPRECATED_IDENTITY_EQUALS!>b !== b<!>
val test_ss = <!DEPRECATED_IDENTITY_EQUALS!>s === s<!> || <!DEPRECATED_IDENTITY_EQUALS!>s !== s<!>
val test_ii = <!DEPRECATED_IDENTITY_EQUALS!>i === i<!> || <!DEPRECATED_IDENTITY_EQUALS!>i !== i<!>
val test_jj = <!DEPRECATED_IDENTITY_EQUALS!>j === j<!> || <!DEPRECATED_IDENTITY_EQUALS!>j !== j<!>
val test_ff = <!DEPRECATED_IDENTITY_EQUALS!>f === f<!> || <!DEPRECATED_IDENTITY_EQUALS!>f !== f<!>
val test_dd = <!DEPRECATED_IDENTITY_EQUALS!>d === d<!> || <!DEPRECATED_IDENTITY_EQUALS!>d !== d<!>
val test_cc = <!DEPRECATED_IDENTITY_EQUALS!>c === c<!> || <!DEPRECATED_IDENTITY_EQUALS!>c !== c<!>
// Identity for primitive values of different types (no extra error)
val test_zb = <!EQUALITY_NOT_APPLICABLE_WARNING!>z === b<!> || <!EQUALITY_NOT_APPLICABLE_WARNING!>z !== b<!>
val test_zb = <!FORBIDDEN_IDENTITY_EQUALS!>z === b<!> || <!FORBIDDEN_IDENTITY_EQUALS!>z !== b<!>
// Primitive vs nullable
val test_znz = z === nz || nz === z || z !== nz || nz !== z
val test_bnb = b === nb || nb === b || b !== nb || nb !== b
val test_sns = s === ns || ns === s || s !== ns || ns !== s
val test_ini = i === ni || ni === i || i !== ni || ni !== i
val test_jnj = j === nj || nj === j || j !== nj || nj !== j
val test_fnf = f === nf || nf === f || f !== nf || nf !== f
val test_dnd = d === nd || nd === d || d !== nd || nd !== d
val test_cnc = c === nc || nc === c || c !== nc || nc !== c
val test_znz = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>z === nz<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nz === z<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>z !== nz<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nz !== z<!>
val test_bnb = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>b === nb<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nb === b<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>b !== nb<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nb !== b<!>
val test_sns = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>s === ns<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>ns === s<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>s !== ns<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>ns !== s<!>
val test_ini = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>i === ni<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>ni === i<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>i !== ni<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>ni !== i<!>
val test_jnj = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>j === nj<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nj === j<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>j !== nj<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nj !== j<!>
val test_fnf = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>f === nf<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nf === f<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>f !== nf<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nf !== f<!>
val test_dnd = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>d === nd<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nd === d<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>d !== nd<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nd !== d<!>
val test_cnc = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>c === nc<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nc === c<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>c !== nc<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nc !== c<!>
// Primitive number vs Number
val test_bn = b === n || n === b || b !== n || n !== b
val test_sn = s === n || n === s || s !== n || n !== s
val test_in = i === n || n === i || i !== n || n !== i
val test_jn = j === n || n === j || j !== n || n !== j
val test_fn = f === n || n === f || f !== n || n !== f
val test_dn = d === n || n === d || d !== n || n !== d
val test_bn = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>b === n<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>n === b<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>b !== n<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>n !== b<!>
val test_sn = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>s === n<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>n === s<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>s !== n<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>n !== s<!>
val test_in = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>i === n<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>n === i<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>i !== n<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>n !== i<!>
val test_jn = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>j === n<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>n === j<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>j !== n<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>n !== j<!>
val test_fn = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>f === n<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>n === f<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>f !== n<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>n !== f<!>
val test_dn = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>d === n<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>n === d<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>d !== n<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>n !== d<!>
// Primitive number vs Number?
val test_bnn = b === nn || nn === b || b !== nn || nn !== b
val test_snn = s === nn || nn === s || s !== nn || nn !== s
val test_inn = i === nn || nn === i || i !== nn || nn !== i
val test_jnn = j === nn || nn === j || j !== nn || nn !== j
val test_fnn = f === nn || nn === f || f !== nn || nn !== f
val test_dnn = d === nn || nn === d || d !== nn || nn !== d
val test_bnn = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>b === nn<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nn === b<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>b !== nn<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nn !== b<!>
val test_snn = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>s === nn<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nn === s<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>s !== nn<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nn !== s<!>
val test_inn = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>i === nn<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nn === i<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>i !== nn<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nn !== i<!>
val test_jnn = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>j === nn<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nn === j<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>j !== nn<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nn !== j<!>
val test_fnn = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>f === nn<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nn === f<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>f !== nn<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nn !== f<!>
val test_dnn = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>d === nn<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nn === d<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>d !== nn<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>nn !== d<!>
// Primitive vs Any
val test_za = z === a || a === z || z !== a || a !== z
val test_ba = b === a || a === b || b !== a || a !== b
val test_sa = s === a || a === s || s !== a || a !== s
val test_ia = i === a || a === i || i !== a || a !== i
val test_ja = j === a || a === j || j !== a || a !== j
val test_fa = f === a || a === f || f !== a || a !== f
val test_da = d === a || a === d || d !== a || a !== d
val test_ca = c === a || a === c || c !== a || a !== c
val test_za = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>z === a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a === z<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>z !== a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a !== z<!>
val test_ba = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>b === a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a === b<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>b !== a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a !== b<!>
val test_sa = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>s === a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a === s<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>s !== a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a !== s<!>
val test_ia = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>i === a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a === i<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>i !== a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a !== i<!>
val test_ja = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>j === a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a === j<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>j !== a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a !== j<!>
val test_fa = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>f === a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a === f<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>f !== a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a !== f<!>
val test_da = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>d === a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a === d<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>d !== a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a !== d<!>
val test_ca = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>c === a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a === c<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>c !== a<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a !== c<!>
// Primitive vs Any?
val test_zna = z === na || na === z || z !== na || na !== z
val test_bna = b === na || na === b || b !== na || na !== b
val test_sna = s === na || na === s || s !== na || na !== s
val test_ina = i === na || na === i || i !== na || na !== i
val test_jna = j === na || na === j || j !== na || na !== j
val test_fna = f === na || na === f || f !== na || na !== f
val test_dna = d === na || na === d || d !== na || na !== d
val test_cna = c === na || na === c || c !== na || na !== c
val test_zna = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>z === na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na === z<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>z !== na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na !== z<!>
val test_bna = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>b === na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na === b<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>b !== na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na !== b<!>
val test_sna = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>s === na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na === s<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>s !== na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na !== s<!>
val test_ina = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>i === na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na === i<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>i !== na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na !== i<!>
val test_jna = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>j === na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na === j<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>j !== na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na !== j<!>
val test_fna = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>f === na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na === f<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>f !== na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na !== f<!>
val test_dna = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>d === na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na === d<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>d !== na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na !== d<!>
val test_cna = <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>c === na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na === c<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>c !== na<!> || <!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>na !== c<!>
@@ -5,5 +5,5 @@ class Bar3 : Foo<Bar3>
fun test(b1: Bar1, b2: Bar2, b3: Bar3) {
b1 == b2
<!EQUALITY_NOT_APPLICABLE_WARNING!>b1 == b3<!>
b1 == b3
}
@@ -0,0 +1,9 @@
// ISSUE: KT-29316
// ISSUE: KT-24284
class A
class B
fun main() {
A() == B()
A() === B()
}
@@ -0,0 +1,9 @@
// ISSUE: KT-29316
// ISSUE: KT-24284
class A
class B
fun main() {
<!EQUALITY_NOT_APPLICABLE!>A() == B()<!>
<!EQUALITY_NOT_APPLICABLE!>A() === B()<!>
}
@@ -0,0 +1,23 @@
// FIR_IDENTICAL
// ISSUE: KT-13451
// FILE: J.java
public class J {
}
// FILE: Main.kt
class K {
fun f() {}
}
fun test (j: J, k: K) {
j == K::f
j == k::f
when (j) {
k::f -> ""
K::f -> ""
}
}
@@ -0,0 +1,7 @@
// FIR_IDENTICAL
// ISSUE: KT-47884
interface A<X>
class B<T>
fun foo(a: A<*>, b: B<*>): Boolean = a == b
@@ -0,0 +1,7 @@
// ISSUE: KT-22499
fun test(x: Any, y: Any) =
x is Float && y is Double && <!EQUALITY_NOT_APPLICABLE_WARNING!>x == y<!>
fun test(x: Float, y: Double) =
<!EQUALITY_NOT_APPLICABLE!>x == y<!>
@@ -0,0 +1,7 @@
// ISSUE: KT-22499
fun test(x: Any, y: Any) =
x is Float && y is Double && x == y
fun test(x: Float, y: Double) =
<!EQUALITY_NOT_APPLICABLE!>x == y<!>
@@ -1,17 +0,0 @@
// !LANGUAGE: -ProhibitComparisonOfIncompatibleEnums
// FILE: JavaEnumA.java
public enum JavaEnumA {}
// FILE: JavaEnumB.java
public enum JavaEnumB {}
// FILE: test.kt
enum class KotlinEnumA
enum class KotlinEnumB
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<!>
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: -ProhibitComparisonOfIncompatibleEnums
// FILE: JavaEnumA.java
@@ -0,0 +1,63 @@
interface Buffered {
fun flush()
}
interface AIPowered {
fun getAvatarReleaseYear(): Int
}
enum class BufferedEnum : Buffered {
A, B;
override fun flush() {}
}
enum class UsualEnum {
C, D;
}
enum class CleverEnum : Buffered, AIPowered {
E, F;
override fun flush() {}
override fun getAvatarReleaseYear() = 2022
}
fun <P> processInfo1(info: String, printer: P) where P: Buffered, P: AIPowered {
<!EQUALITY_NOT_APPLICABLE!>printer == 20<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>printer == BufferedEnum.A<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>printer == UsualEnum.C<!>
printer == CleverEnum.E
}
fun <P> processInfo2(info: String, printer: P) where P: AIPowered, P: Buffered {
<!EQUALITY_NOT_APPLICABLE!>printer == 20<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>printer == BufferedEnum.A<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>printer == UsualEnum.C<!>
printer == CleverEnum.E
}
abstract class Printer {
abstract fun print(command: String)
}
fun <P> processInfo3(info: String, printer: P) where P: Buffered, P: Printer {
<!EQUALITY_NOT_APPLICABLE!>printer == 20<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>printer == BufferedEnum.A<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>printer == UsualEnum.C<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>printer == CleverEnum.E<!>
}
fun test(a: Int, b: Any?) {
<!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a === b<!>
}
fun <<!CONFLICTING_UPPER_BOUNDS, INCONSISTENT_TYPE_PARAMETER_BOUNDS, MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>T: <!FINAL_UPPER_BOUND!>Int<!><!>> rest(a: T, b: Any?) where T : <!FINAL_UPPER_BOUND, ONLY_ONE_CLASS_BOUND_ALLOWED!>String<!> {
<!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a === b<!>
}
fun <<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>T: Any?<!>> nest(a: Int, b: T) where T : <!FINAL_UPPER_BOUND, ONLY_ONE_CLASS_BOUND_ALLOWED!>String<!> {
<!FORBIDDEN_IDENTITY_EQUALS!>a === b<!>
}
fun <<!CONFLICTING_UPPER_BOUNDS, INCONSISTENT_TYPE_PARAMETER_BOUNDS, MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>T: <!FINAL_UPPER_BOUND!>Int<!><!>, <!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>K: Any?<!>> mest(a: T, b: K) where T : <!FINAL_UPPER_BOUND, ONLY_ONE_CLASS_BOUND_ALLOWED!>String<!>, K: <!FINAL_UPPER_BOUND, ONLY_ONE_CLASS_BOUND_ALLOWED!>Boolean<!> {
<!FORBIDDEN_IDENTITY_EQUALS_WARNING!>a === b<!>
}
@@ -0,0 +1,63 @@
interface Buffered {
fun flush()
}
interface AIPowered {
fun getAvatarReleaseYear(): Int
}
enum class BufferedEnum : Buffered {
A, B;
override fun flush() {}
}
enum class UsualEnum {
C, D;
}
enum class CleverEnum : Buffered, AIPowered {
E, F;
override fun flush() {}
override fun getAvatarReleaseYear() = 2022
}
fun <P> processInfo1(info: String, printer: P) where P: Buffered, P: AIPowered {
<!EQUALITY_NOT_APPLICABLE!>printer == 20<!>
printer == BufferedEnum.A
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>printer == UsualEnum.C<!>
printer == CleverEnum.E
}
fun <P> processInfo2(info: String, printer: P) where P: AIPowered, P: Buffered {
<!EQUALITY_NOT_APPLICABLE!>printer == 20<!>
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>printer == BufferedEnum.A<!>
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>printer == UsualEnum.C<!>
printer == CleverEnum.E
}
abstract class Printer {
abstract fun print(command: String)
}
fun <P> processInfo3(info: String, printer: P) where P: Buffered, P: Printer {
<!EQUALITY_NOT_APPLICABLE!>printer == 20<!>
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>printer == BufferedEnum.A<!>
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>printer == UsualEnum.C<!>
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>printer == CleverEnum.E<!>
}
fun test(a: Int, b: Any?) {
<!IMPLICIT_BOXING_IN_IDENTITY_EQUALS!>a === b<!>
}
fun <<!INCONSISTENT_TYPE_PARAMETER_BOUNDS, MISPLACED_TYPE_PARAMETER_CONSTRAINTS!><!CONFLICTING_UPPER_BOUNDS!>T<!>: <!FINAL_UPPER_BOUND!>Int<!><!>> rest(a: T, b: Any?) where T : <!FINAL_UPPER_BOUND, ONLY_ONE_CLASS_BOUND_ALLOWED!>String<!> {
a === b
}
fun <<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>T: Any?<!>> nest(a: Int, b: T) where T : <!FINAL_UPPER_BOUND, ONLY_ONE_CLASS_BOUND_ALLOWED!>String<!> {
<!EQUALITY_NOT_APPLICABLE!>a === b<!>
}
fun <<!INCONSISTENT_TYPE_PARAMETER_BOUNDS, MISPLACED_TYPE_PARAMETER_CONSTRAINTS!><!CONFLICTING_UPPER_BOUNDS!>T<!>: <!FINAL_UPPER_BOUND!>Int<!><!>, <!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>K: Any?<!>> mest(a: T, b: K) where T : <!FINAL_UPPER_BOUND, ONLY_ONE_CLASS_BOUND_ALLOWED!>String<!>, K: <!FINAL_UPPER_BOUND, ONLY_ONE_CLASS_BOUND_ALLOWED!>Boolean<!> {
a === b
}
@@ -0,0 +1,13 @@
// FILE: A.java
class MyHelpers {
public static <T> T id(T it) {
return it;
}
}
// FILE: B.kt
fun <<!CONFLICTING_UPPER_BOUNDS, INCONSISTENT_TYPE_PARAMETER_BOUNDS, MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>T: <!FINAL_UPPER_BOUND!>Int<!><!>, <!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>K: Any?<!>> mest(a: T, b: K) where T : <!FINAL_UPPER_BOUND, ONLY_ONE_CLASS_BOUND_ALLOWED!>String<!>, K: <!FINAL_UPPER_BOUND, ONLY_ONE_CLASS_BOUND_ALLOWED!>Boolean<!> {
<!FORBIDDEN_IDENTITY_EQUALS_WARNING!>MyHelpers.id(a) === MyHelpers.id(b)<!>
}
@@ -0,0 +1,13 @@
// FILE: A.java
class MyHelpers {
public static <T> T id(T it) {
return it;
}
}
// FILE: B.kt
fun <<!INCONSISTENT_TYPE_PARAMETER_BOUNDS, MISPLACED_TYPE_PARAMETER_CONSTRAINTS!><!CONFLICTING_UPPER_BOUNDS!>T<!>: <!FINAL_UPPER_BOUND!>Int<!><!>, <!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>K: Any?<!>> mest(a: T, b: K) where T : <!FINAL_UPPER_BOUND, ONLY_ONE_CLASS_BOUND_ALLOWED!>String<!>, K: <!FINAL_UPPER_BOUND, ONLY_ONE_CLASS_BOUND_ALLOWED!>Boolean<!> {
MyHelpers.id(a) === MyHelpers.id(b)
}
@@ -1,92 +0,0 @@
// !LANGUAGE: -ProhibitComparisonOfIncompatibleEnums
interface I {
fun foo()
}
enum class E1 : I {
A {
override fun foo() {
<!EQUALITY_NOT_APPLICABLE_WARNING!>this == E2.A<!>
val q = this
when (q) {
this -> {}
E1.A -> {}
E1.B -> {}
<!INCOMPATIBLE_TYPES_WARNING!>E2.A<!> -> {}
<!INCOMPATIBLE_TYPES_WARNING!>E2.B<!> -> {}
else -> {}
}
}
},
B {
override fun foo() {
}
}
}
enum class E2 : I {
A {
override fun foo() {
}
},
B {
override fun foo() {
}
}
}
fun foo1(e1: E1, e2: E2) {
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == e2<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 != e2<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == E2.A<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>E1.B == e2<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>E1.A == E2.B<!>
e1 == E1.A
E1.A == e1
e2 == E2.B
E2.B == e2
}
fun foo2(e1: E1, e2: E2) {
when (e1) {
E1.A -> {}
<!INCOMPATIBLE_TYPES_WARNING!>E2.A<!> -> {}
<!INCOMPATIBLE_TYPES_WARNING!>E2.B<!> -> {}
e1 -> {}
<!INCOMPATIBLE_TYPES_WARNING!>e2<!> -> {}
else -> {}
}
}
fun foo3(e1: Enum<E1>, e2: Enum<E2>, e: Enum<*>) {
e1 == e
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == e2<!>
e1 == E1.A
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == E2.A<!>
when (e1) {
e1 -> {}
<!INCOMPATIBLE_TYPES_WARNING!>e2<!> -> {}
e -> {}
E1.A -> {}
<!INCOMPATIBLE_TYPES_WARNING!>E2.A<!> -> {}
else -> {}
}
when (e) {
e -> {}
e2 -> {}
E1.A -> {}
E2.A -> {}
else -> {}
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: -ProhibitComparisonOfIncompatibleEnums
interface I {
@@ -9,13 +9,13 @@ enum class E2 {
}
fun foo1(e1: E1, e2: E2) {
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == e2<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 != e2<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 == e2<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 != e2<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == E2.A<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>E1.B == e2<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 == E2.A<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>E1.B == e2<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>E1.A == E2.B<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>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 -> {}
<!INCOMPATIBLE_TYPES_WARNING!>E2.A<!> -> {}
<!INCOMPATIBLE_TYPES_WARNING!>E2.B<!> -> {}
<!INCOMPATIBLE_ENUM_COMPARISON!>E2.A<!> -> {}
<!INCOMPATIBLE_ENUM_COMPARISON!>E2.B<!> -> {}
e1 -> {}
<!INCOMPATIBLE_TYPES_WARNING!>e2<!> -> {}
<!INCOMPATIBLE_ENUM_COMPARISON!>e2<!> -> {}
else -> {}
}
}
fun foo3(e1: Enum<E1>, e2: Enum<E2>, e: Enum<*>) {
e1 == e
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == e2<!>
e1 == e2
e1 == E1.A
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == E2.A<!>
e1 == E2.A
when (e1) {
e1 -> {}
<!INCOMPATIBLE_TYPES_WARNING!>e2<!> -> {}
e2 -> {}
e -> {}
E1.A -> {}
<!INCOMPATIBLE_TYPES_WARNING!>E2.A<!> -> {}
E2.A -> {}
else -> {}
}
@@ -63,15 +63,15 @@ interface MyInterface
open class MyOpenClass
fun foo4(e1: E1, i: MyInterface, c: MyOpenClass) {
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == i<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>i == e1<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 == i<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>i == e1<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == c<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>c == e1<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 == c<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>c == e1<!>
when (e1) {
<!INCOMPATIBLE_TYPES_WARNING!>i<!> -> {}
<!INCOMPATIBLE_TYPES_WARNING!>c<!> -> {}
<!INCOMPATIBLE_ENUM_COMPARISON!>i<!> -> {}
<!INCOMPATIBLE_ENUM_COMPARISON!>c<!> -> {}
else -> {}
}
}
@@ -90,10 +90,10 @@ fun foo6(e1: E1?, e2: E2) {
e1 == null
null == 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<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 == E2.A<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>E2.A == e1<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 == e2<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>e2 == e1<!>
<!SENSELESS_COMPARISON!>e2 == null<!>
<!SENSELESS_COMPARISON!>null == e2<!>
@@ -102,7 +102,7 @@ fun foo6(e1: E1?, e2: E2) {
}
fun foo7(e1: E1?, e2: E2?) {
e1 == e2 // There should be an IDE-inspection for such cases
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 == e2<!> // There should be an IDE-inspection for such cases
}
fun <T> foo8(e1: E1?, e2: E2, t: T) {
@@ -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 {
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == t<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>t == e1<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 == t<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>t == e1<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>e2 == t<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>t == e2<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>e2 == t<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>t == e2<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>E1.A == t<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>t == E1.A<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>E1.A == t<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>t == E1.A<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>E3.X == t<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>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>) {
<!EQUALITY_NOT_APPLICABLE_WARNING!>e4 == invString<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>invString == e4<!>
e4 == invString
invString == e4
<!EQUALITY_NOT_APPLICABLE_WARNING!>E4.A == invString<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>invString == E4.A<!>
E4.A == invString
invString == E4.A
}
@@ -26,27 +26,27 @@ fun foo1(e1: E1, e2: E2) {
fun foo2(e1: E1, e2: E2) {
when (e1) {
E1.A -> {}
<!INCOMPATIBLE_TYPES!>E2.A<!> -> {}
<!INCOMPATIBLE_TYPES!>E2.B<!> -> {}
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>E2.A<!> -> {}
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>E2.B<!> -> {}
e1 -> {}
<!INCOMPATIBLE_TYPES!>e2<!> -> {}
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e2<!> -> {}
else -> {}
}
}
fun foo3(e1: Enum<E1>, e2: Enum<E2>, e: Enum<*>) {
e1 == e
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == e2<!>
e1 == e2
e1 == E1.A
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e1 == E2.A<!>
e1 == E2.A
when (e1) {
e1 -> {}
<!INCOMPATIBLE_TYPES!>e2<!> -> {}
e2 -> {}
e -> {}
E1.A -> {}
<!INCOMPATIBLE_TYPES!>E2.A<!> -> {}
E2.A -> {}
else -> {}
}
@@ -70,8 +70,8 @@ fun foo4(e1: E1, i: MyInterface, c: MyOpenClass) {
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>c == e1<!>
when (e1) {
<!INCOMPATIBLE_TYPES!>i<!> -> {}
<!INCOMPATIBLE_TYPES!>c<!> -> {}
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>i<!> -> {}
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>c<!> -> {}
else -> {}
}
}
@@ -102,7 +102,7 @@ fun foo6(e1: E1?, e2: E2) {
}
fun foo7(e1: E1?, e2: E2?) {
e1 == e2 // There should be an IDE-inspection for such cases
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 == e2<!> // There should be an IDE-inspection for such cases
}
fun <T> foo8(e1: E1?, e2: E2, t: T) {
@@ -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 {
<!EQUALITY_NOT_APPLICABLE_WARNING!>e1 == t<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>t == e1<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>e1 == t<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>t == e1<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>e2 == t<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>t == e2<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>e2 == t<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>t == e2<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>E1.A == t<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>t == E1.A<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>E1.A == t<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>t == E1.A<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>E3.X == t<!>
<!INCOMPATIBLE_ENUM_COMPARISON!>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>) {
<!EQUALITY_NOT_APPLICABLE_WARNING!>e4 == invString<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>invString == e4<!>
e4 == invString
invString == e4
<!EQUALITY_NOT_APPLICABLE_WARNING!>E4.A == invString<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>invString == E4.A<!>
E4.A == invString
invString == E4.A
}
@@ -56,47 +56,47 @@ fun foo(
<!EQUALITY_NOT_APPLICABLE!>"" == 2<!>
<!EQUALITY_NOT_APPLICABLE!>string == int<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>strings == ints<!>
strings == ints
<!EQUALITY_NOT_APPLICABLE_WARNING!>aString == aInt<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>aOutString == aOutInt<!>
aString == aInt
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<!>
aOutString == aInInt
aInString == aOutInt
aOutString == aInt
aInString == aInt
aOutString2 == aOutInt2
aInString2 == aInInt2
<!EQUALITY_NOT_APPLICABLE_WARNING!>aOutString2 == aInInt2<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>aInString2 == aOutInt2<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>aString == a2<!>
aOutString2 == aInInt2
aInString2 == aOutInt2
aString == a2
<!EQUALITY_NOT_APPLICABLE_WARNING!>bString == bInt<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>bOutString == bOutInt<!>
bString == bInt
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<!>
bOutString == bInInt
bInString == bOutInt
bOutString == bInt
bInString == bInt
bOutString2 == bOutInt2
bInString2 == bInInt2
<!EQUALITY_NOT_APPLICABLE_WARNING!>bOutString2 == bInInt2<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>bInString2 == bOutInt2<!>
bOutString2 == bInInt2
bInString2 == bOutInt2
<!INCOMPATIBLE_ENUM_COMPARISON_ERROR!>e == i<!>
<!EQUALITY_NOT_APPLICABLE!>"" == i<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>ac == ad<!>
ac == ad
<!EQUALITY_NOT_APPLICABLE_WARNING!>tSub1 == tSub2<!>
tSub1 == tSub2
<!EQUALITY_NOT_APPLICABLE_WARNING!>aString == bString<!>
aString == bString
<!EQUALITY_NOT_APPLICABLE_WARNING!>aListInt == aSetInt<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>aSetInt == aListString<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>aListString == aListInt<!>
aListInt == aSetInt
aSetInt == aListString
aListString == aListInt
<!EQUALITY_NOT_APPLICABLE_WARNING!>aString == aListString<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>bString == aListString<!>
aString == aListString
bString == aListString
<!EQUALITY_NOT_APPLICABLE_WARNING!>mutableListAny == listString<!>
mutableListAny == listString
}
@@ -0,0 +1,7 @@
// FIR_IDENTICAL
// ISSUE: KTIJ-15380
fun test() {
var x = 0
if (x == x) {}
}
@@ -0,0 +1,8 @@
// ISSUE: KT-46383
fun test(a: Any, b: Any, s: String, i: Int) {
if (a is String && b is Int) {
<!EQUALITY_NOT_APPLICABLE_WARNING!>a == b<!>
}
<!EQUALITY_NOT_APPLICABLE!>s == i<!>
}
@@ -0,0 +1,8 @@
// ISSUE: KT-46383
fun test(a: Any, b: Any, s: String, i: Int) {
if (a is String && b is Int) {
a == b
}
<!EQUALITY_NOT_APPLICABLE!>s == i<!>
}
@@ -3,18 +3,18 @@
fun main(x: Long, y: Int) {
sequence {
<!EQUALITY_NOT_APPLICABLE_WARNING!>1L == 3<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>x == 3<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>3 == 1L<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>3 == x<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>y == x<!>
<!EQUALITY_NOT_APPLICABLE!>1L == 3<!>
<!EQUALITY_NOT_APPLICABLE!>x == 3<!>
<!EQUALITY_NOT_APPLICABLE!>3 == 1L<!>
<!EQUALITY_NOT_APPLICABLE!>3 == x<!>
<!EQUALITY_NOT_APPLICABLE!>y == x<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>1L === 3<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>x === 3<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>3 === 1L<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>3 === x<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>y === x<!>
<!FORBIDDEN_IDENTITY_EQUALS!>1L === 3<!>
<!FORBIDDEN_IDENTITY_EQUALS!>x === 3<!>
<!FORBIDDEN_IDENTITY_EQUALS!>3 === 1L<!>
<!FORBIDDEN_IDENTITY_EQUALS!>3 === x<!>
<!FORBIDDEN_IDENTITY_EQUALS!>y === x<!>
yield("")
}
}
}
@@ -3,18 +3,18 @@
fun main(x: Long, y: Int) {
sequence {
<!EQUALITY_NOT_APPLICABLE_WARNING!>1L == 3<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>x == 3<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>3 == 1L<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>3 == x<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>y == x<!>
<!EQUALITY_NOT_APPLICABLE!>1L == 3<!>
<!EQUALITY_NOT_APPLICABLE!>x == 3<!>
<!EQUALITY_NOT_APPLICABLE!>3 == 1L<!>
<!EQUALITY_NOT_APPLICABLE!>3 == x<!>
<!EQUALITY_NOT_APPLICABLE!>y == x<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>1L === 3<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>x === 3<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>3 === 1L<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>3 === x<!>
<!EQUALITY_NOT_APPLICABLE_WARNING!>y === x<!>
<!FORBIDDEN_IDENTITY_EQUALS!>1L === 3<!>
<!FORBIDDEN_IDENTITY_EQUALS!>x === 3<!>
<!FORBIDDEN_IDENTITY_EQUALS!>3 === 1L<!>
<!FORBIDDEN_IDENTITY_EQUALS!>3 === x<!>
<!FORBIDDEN_IDENTITY_EQUALS!>y === x<!>
yield("")
}
}
}
@@ -5,18 +5,18 @@ inline class Foo(val x: Int)
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 = <!EQUALITY_NOT_APPLICABLE!>f1 === b1<!> || <!EQUALITY_NOT_APPLICABLE!>f1 !== b1<!>
val a1 = <!FORBIDDEN_IDENTITY_EQUALS!>f1 === f2<!> || <!FORBIDDEN_IDENTITY_EQUALS!>f1 !== f2<!>
val a2 = <!FORBIDDEN_IDENTITY_EQUALS!>f1 === f1<!>
val a3 = <!FORBIDDEN_IDENTITY_EQUALS!>f1 === b1<!> || <!FORBIDDEN_IDENTITY_EQUALS!>f1 !== b1<!>
val c1 = fn1 === fn2 || fn1 !== fn2
val c2 = f1 === fn1 || f1 !== fn1
val c3 = <!EQUALITY_NOT_APPLICABLE!>b1 === fn1<!> || <!EQUALITY_NOT_APPLICABLE!>b1 !== fn1<!>
val c2 = <!FORBIDDEN_IDENTITY_EQUALS!>f1 === fn1<!> || <!FORBIDDEN_IDENTITY_EQUALS!>f1 !== fn1<!>
val c3 = <!FORBIDDEN_IDENTITY_EQUALS!>b1 === fn1<!> || <!FORBIDDEN_IDENTITY_EQUALS!>b1 !== fn1<!>
val any = Any()
val d1 = any === f1 || any !== f1
val d2 = f1 === any || f1 !== any
val d1 = <!FORBIDDEN_IDENTITY_EQUALS!>any === f1<!> || <!FORBIDDEN_IDENTITY_EQUALS!>any !== f1<!>
val d2 = <!FORBIDDEN_IDENTITY_EQUALS!>f1 === any<!> || <!FORBIDDEN_IDENTITY_EQUALS!>f1 !== any<!>
val d3 = any === fn1 || any !== fn1
val d4 = fn1 === any || fn1 !== any
}
@@ -3,12 +3,12 @@
const val equalsBoolean1 = true.equals(true)
const val equalsBoolean2 = false != true
const val equalsBoolean3 = false.equals(1)
const val equalsBoolean4 = <!EQUALITY_NOT_APPLICABLE_WARNING!>false == 1<!>
const val equalsBoolean4 = <!EQUALITY_NOT_APPLICABLE!>false == 1<!>
const val equalsChar1 = '1'.equals('2')
const val equalsChar2 = '2' == '2'
const val equalsChar3 = '1'.equals(1)
const val equalsChar4 = <!EQUALITY_NOT_APPLICABLE_WARNING!>'1' == 1<!>
const val equalsChar4 = <!EQUALITY_NOT_APPLICABLE!>'1' == 1<!>
const val equalsByte1 = 1.toByte().equals(2.toByte())
const val equalsByte2 = 2.toByte() == 2.toByte()
@@ -3,12 +3,12 @@
const val equalsBoolean1 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>true.equals(true)<!>
const val equalsBoolean2 = false != true
const val equalsBoolean3 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>false.equals(1)<!>
const val equalsBoolean4 = <!EQUALITY_NOT_APPLICABLE_WARNING!>false == 1<!>
const val equalsBoolean4 = <!EQUALITY_NOT_APPLICABLE!>false == 1<!>
const val equalsChar1 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>'1'.equals('2')<!>
const val equalsChar2 = '2' == '2'
const val equalsChar3 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>'1'.equals(1)<!>
const val equalsChar4 = <!EQUALITY_NOT_APPLICABLE_WARNING!>'1' == 1<!>
const val equalsChar4 = <!EQUALITY_NOT_APPLICABLE!>'1' == 1<!>
const val equalsByte1 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>1.toByte().equals(2.toByte())<!>
const val equalsByte2 = 2.toByte() == 2.toByte()
@@ -8,8 +8,8 @@ import checkSubtype
fun main(args : Array<String>) {
val x = checkSubtype<Any>(args[0])
if(x is <!PLATFORM_CLASS_MAPPED_TO_KOTLIN!>java.lang.CharSequence<!>) {
if (<!EQUALITY_NOT_APPLICABLE!>"a" == x<!>) x.<!FUNCTION_CALL_EXPECTED!>length<!> else x.length() // OK
if (<!EQUALITY_NOT_APPLICABLE!>"a" == x<!> || <!EQUALITY_NOT_APPLICABLE!>"b" == x<!>) x.<!FUNCTION_CALL_EXPECTED!>length<!> else x.length() // < THEN ERROR
if (<!EQUALITY_NOT_APPLICABLE!>"a" == x<!> && <!EQUALITY_NOT_APPLICABLE!>"a" == x<!>) x.<!FUNCTION_CALL_EXPECTED!>length<!> else x.length() // < ELSE ERROR
if (<!EQUALITY_NOT_APPLICABLE_WARNING!>"a" == x<!>) x.<!FUNCTION_CALL_EXPECTED!>length<!> else x.length() // OK
if (<!EQUALITY_NOT_APPLICABLE_WARNING!>"a" == x<!> || <!EQUALITY_NOT_APPLICABLE_WARNING!>"b" == x<!>) x.<!FUNCTION_CALL_EXPECTED!>length<!> else x.length() // < THEN ERROR
if (<!EQUALITY_NOT_APPLICABLE_WARNING!>"a" == x<!> && <!EQUALITY_NOT_APPLICABLE_WARNING!>"a" == x<!>) x.<!FUNCTION_CALL_EXPECTED!>length<!> else x.length() // < ELSE ERROR
}
}
@@ -11,7 +11,7 @@ sealed class Tree {
fun maxIsClass(): Int = <!NO_ELSE_IN_WHEN!>when<!>(this) {
Empty -> -1
<!INCOMPATIBLE_TYPES, NO_COMPANION_OBJECT!>Leaf<!> -> 0
<!NO_COMPANION_OBJECT!>Leaf<!> -> 0
is Node -> this.left.max()
}
@@ -6,18 +6,18 @@ fun test(
ui1: UInt, ui2: UInt,
ul1: ULong, ul2: ULong
) {
val ub = ub1 === ub2 || ub1 !== ub2
val us = us1 === us2 || us1 !== us2
val ui = ui1 === ui2 || ui1 !== ui2
val ul = ul1 === ul2 || ul1 !== ul2
val ub = <!FORBIDDEN_IDENTITY_EQUALS!>ub1 === ub2<!> || <!FORBIDDEN_IDENTITY_EQUALS!>ub1 !== ub2<!>
val us = <!FORBIDDEN_IDENTITY_EQUALS!>us1 === us2<!> || <!FORBIDDEN_IDENTITY_EQUALS!>us1 !== us2<!>
val ui = <!FORBIDDEN_IDENTITY_EQUALS!>ui1 === ui2<!> || <!FORBIDDEN_IDENTITY_EQUALS!>ui1 !== ui2<!>
val ul = <!FORBIDDEN_IDENTITY_EQUALS!>ul1 === ul2<!> || <!FORBIDDEN_IDENTITY_EQUALS!>ul1 !== ul2<!>
val u = <!EQUALITY_NOT_APPLICABLE!>ub1 === ul1<!>
val u = <!FORBIDDEN_IDENTITY_EQUALS!>ub1 === ul1<!>
val a1 = 1u === 2u || 1u !== 2u
val a2 = 0xFFFF_FFFF_FFFF_FFFFu === 0xFFFF_FFFF_FFFF_FFFFu
val a1 = <!FORBIDDEN_IDENTITY_EQUALS!>1u === 2u<!> || <!FORBIDDEN_IDENTITY_EQUALS!>1u !== 2u<!>
val a2 = <!FORBIDDEN_IDENTITY_EQUALS!>0xFFFF_FFFF_FFFF_FFFFu === 0xFFFF_FFFF_FFFF_FFFFu<!>
val bu1 = 1u
val bu2 = 1u
val c1 = bu1 === bu2 || bu1 !== bu2
val c1 = <!FORBIDDEN_IDENTITY_EQUALS!>bu1 === bu2<!> || <!FORBIDDEN_IDENTITY_EQUALS!>bu1 !== bu2<!>
}
@@ -13,18 +13,18 @@ value class Foo(val x: Int)
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 = <!EQUALITY_NOT_APPLICABLE!>f1 === b1<!> || <!EQUALITY_NOT_APPLICABLE!>f1 !== b1<!>
val a1 = <!FORBIDDEN_IDENTITY_EQUALS!>f1 === f2<!> || <!FORBIDDEN_IDENTITY_EQUALS!>f1 !== f2<!>
val a2 = <!FORBIDDEN_IDENTITY_EQUALS!>f1 === f1<!>
val a3 = <!FORBIDDEN_IDENTITY_EQUALS!>f1 === b1<!> || <!FORBIDDEN_IDENTITY_EQUALS!>f1 !== b1<!>
val c1 = fn1 === fn2 || fn1 !== fn2
val c2 = f1 === fn1 || f1 !== fn1
val c3 = <!EQUALITY_NOT_APPLICABLE!>b1 === fn1<!> || <!EQUALITY_NOT_APPLICABLE!>b1 !== fn1<!>
val c2 = <!FORBIDDEN_IDENTITY_EQUALS!>f1 === fn1<!> || <!FORBIDDEN_IDENTITY_EQUALS!>f1 !== fn1<!>
val c3 = <!FORBIDDEN_IDENTITY_EQUALS!>b1 === fn1<!> || <!FORBIDDEN_IDENTITY_EQUALS!>b1 !== fn1<!>
val any = Any()
val d1 = any === f1 || any !== f1
val d2 = f1 === any || f1 !== any
val d1 = <!FORBIDDEN_IDENTITY_EQUALS!>any === f1<!> || <!FORBIDDEN_IDENTITY_EQUALS!>any !== f1<!>
val d2 = <!FORBIDDEN_IDENTITY_EQUALS!>f1 === any<!> || <!FORBIDDEN_IDENTITY_EQUALS!>f1 !== any<!>
val d3 = any === fn1 || any !== fn1
val d4 = fn1 === any || fn1 !== any
}
+1 -1
View File
@@ -22,7 +22,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
@@ -47,8 +47,8 @@ fun testWithSubject_ok(x: Boolean, y: Boolean?, any: Any, z: Boolean) {
x <!OVERLOAD_RESOLUTION_AMBIGUITY!>>=<!> x -> {}
x == x -> {}
x != x -> {}
x === x -> {}
x !== x -> {}
<!DEPRECATED_IDENTITY_EQUALS!>x === x<!> -> {}
<!DEPRECATED_IDENTITY_EQUALS!>x !== x<!> -> {}
x && x -> {}
x || x -> {}
}