[FIR] Check is for impossibility

^KT-58203 Fixed
^KT-62646
This commit is contained in:
Nikolay Lunyak
2024-02-29 15:39:33 +02:00
committed by Space Team
parent 92d8da621e
commit 88ff93df7f
42 changed files with 110 additions and 83 deletions
@@ -11,7 +11,7 @@ fun test_1(e: Enum) {
val b = <!NO_ELSE_IN_WHEN!>when<!> (e) { val b = <!NO_ELSE_IN_WHEN!>when<!> (e) {
Enum.A -> 1 Enum.A -> 1
Enum.B -> 2 Enum.B -> 2
is String -> 3 <!USELESS_IS_CHECK!>is String<!> -> 3
} }
val c = when (e) { val c = when (e) {
@@ -15,7 +15,7 @@ fun test_1(e: JavaEnum) {
val b = <!NO_ELSE_IN_WHEN!>when<!> (e) { val b = <!NO_ELSE_IN_WHEN!>when<!> (e) {
JavaEnum.A -> 1 JavaEnum.A -> 1
JavaEnum.B -> 2 JavaEnum.B -> 2
is String -> 3 <!USELESS_IS_CHECK!>is String<!> -> 3
}.plus(0) }.plus(0)
val c = when (e) { val c = when (e) {
@@ -15,7 +15,7 @@ fun test_1(e: Base) {
val b = <!NO_ELSE_IN_WHEN!>when<!> (e) { val b = <!NO_ELSE_IN_WHEN!>when<!> (e) {
is Base.A -> 1 is Base.A -> 1
is Base.A.B -> 2 is Base.A.B -> 2
is String -> 3 <!USELESS_IS_CHECK!>is String<!> -> 3
} }
val c = when (e) { val c = when (e) {
@@ -17,7 +17,7 @@ fun test_2(x: Any) {
fun test_3(x: Any) { fun test_3(x: Any) {
when { when {
x !is String -> {} x !is String -> {}
x !is Int -> {} <!USELESS_IS_CHECK!>x !is Int<!> -> {}
else -> { else -> {
x.length x.length
x.inc() x.inc()
@@ -16,7 +16,7 @@ fun test_1(x: Any?) {
when { when {
x !is A -> {} x !is A -> {}
x !is B -> x.foo() x !is B -> x.foo()
x is Int -> { <!USELESS_IS_CHECK!>x is Int<!> -> {
x.foo() x.foo()
x.bar() x.bar()
x.inc() x.inc()
@@ -37,7 +37,7 @@ fun test_2(x: Any?) {
when(x) { when(x) {
!is A -> {} !is A -> {}
!is B -> x.foo() !is B -> x.foo()
is Int -> { <!USELESS_IS_CHECK!>is Int<!> -> {
x.foo() x.foo()
x.bar() x.bar()
x.inc() x.inc()
@@ -67,7 +67,7 @@ fun test_3(x: Any?) {
x.foo() x.foo()
y.foo() y.foo()
} }
is Int -> { <!USELESS_IS_CHECK!>is Int<!> -> {
x.foo() x.foo()
x.bar() x.bar()
x.inc() x.inc()
@@ -53,7 +53,7 @@ fun Any?.test_4() {
<!UNRESOLVED_REFERENCE!>foo<!>() <!UNRESOLVED_REFERENCE!>foo<!>()
this.<!UNRESOLVED_REFERENCE!>bar<!>() this.<!UNRESOLVED_REFERENCE!>bar<!>()
<!UNRESOLVED_REFERENCE!>bar<!>() <!UNRESOLVED_REFERENCE!>bar<!>()
} else if (this !is B) { } else if (<!USELESS_IS_CHECK!>this !is B<!>) {
this.<!UNRESOLVED_REFERENCE!>bar<!>() this.<!UNRESOLVED_REFERENCE!>bar<!>()
<!UNRESOLVED_REFERENCE!>bar<!>() <!UNRESOLVED_REFERENCE!>bar<!>()
this.foo() this.foo()
@@ -13,7 +13,7 @@ fun test1(x: String?): Int? {
@OptIn(ExperimentalContracts::class) @OptIn(ExperimentalContracts::class)
fun test2(x: String?): Int? { fun test2(x: String?): Int? {
<!WRONG_IMPLIES_CONDITION!>contract { <!WRONG_IMPLIES_CONDITION!>contract {
returnsNotNull() implies (x is Boolean) returnsNotNull() implies (<!USELESS_IS_CHECK!>x is Boolean<!>)
}<!> }<!>
return x?.length return x?.length
@@ -20,7 +20,7 @@ fun <T> deserializeAndLoadState(
) {} ) {}
fun use(beforeRunTask: BeforeRunTask<*>) { fun use(beforeRunTask: BeforeRunTask<*>) {
if (beforeRunTask is PersistentStateComponent<*>) { if (<!USELESS_IS_CHECK!>beforeRunTask is PersistentStateComponent<*><!>) {
deserializeAndLoadState(beforeRunTask) deserializeAndLoadState(beforeRunTask)
} }
} }
@@ -14,5 +14,5 @@ fun foo(u: U) {
val w = +i val w = +i
val g = "" !in u val g = "" !in u
val f = "" !is Boolean val f = <!USELESS_IS_CHECK!>"" !is Boolean<!>
} }
@@ -46,9 +46,13 @@ object FirCastOperatorsChecker : FirTypeOperatorCallChecker(MppCheckerKind.Commo
} }
private fun checkIsApplicability(l: TypeInfo, r: TypeInfo, expression: FirTypeOperatorCall, context: CheckerContext): Applicability { private fun checkIsApplicability(l: TypeInfo, r: TypeInfo, expression: FirTypeOperatorCall, context: CheckerContext): Applicability {
val oneIsFinal = l.isFinal || r.isFinal
val oneIsNotNull = !l.type.isNullable || !r.type.isNullable
return when { return when {
isRefinementUseless(context, l.directType.upperBoundIfFlexible(), r.directType, expression) -> Applicability.USELESS_IS_CHECK isRefinementUseless(context, l.directType.upperBoundIfFlexible(), r.directType, expression) -> Applicability.USELESS_IS_CHECK
isCastErased(l.directType, r.directType, context) -> Applicability.CAST_ERASED isCastErased(l.directType, r.directType, context) -> Applicability.CAST_ERASED
oneIsNotNull && oneIsFinal && areUnrelated(l, r, context) -> Applicability.IMPOSSIBLE_IS_CHECK
else -> Applicability.APPLICABLE else -> Applicability.APPLICABLE
} }
} }
@@ -62,13 +66,13 @@ object FirCastOperatorsChecker : FirTypeOperatorCallChecker(MppCheckerKind.Commo
return when { return when {
isRefinementUseless(context, l.directType.upperBoundIfFlexible(), r.directType, expression) -> Applicability.USELESS_CAST isRefinementUseless(context, l.directType.upperBoundIfFlexible(), r.directType, expression) -> Applicability.USELESS_CAST
l.type.isNothing && r.type.isNothingOrNullableNothing -> Applicability.APPLICABLE l.type.isNothing && r.type.isNothingOrNullableNothing -> Applicability.APPLICABLE
r.type.isNothing -> Applicability.IMPOSSIBLE r.type.isNothing -> Applicability.IMPOSSIBLE_CAST
isNullableNothingWithNotNull -> when (expression.operation) { isNullableNothingWithNotNull -> when (expression.operation) {
// (null as? WhatEver) == null // (null as? WhatEver) == null
FirOperation.SAFE_AS -> Applicability.USELESS_CAST FirOperation.SAFE_AS -> Applicability.USELESS_CAST
else -> Applicability.IMPOSSIBLE else -> Applicability.IMPOSSIBLE_CAST
} }
oneIsNotNull && oneIsFinal && areUnrelated(l, r, context) -> Applicability.IMPOSSIBLE oneIsNotNull && oneIsFinal && areUnrelated(l, r, context) -> Applicability.IMPOSSIBLE_CAST
isCastErased(l.directType, r.directType, context) -> Applicability.CAST_ERASED isCastErased(l.directType, r.directType, context) -> Applicability.CAST_ERASED
else -> Applicability.APPLICABLE else -> Applicability.APPLICABLE
} }
@@ -91,7 +95,8 @@ object FirCastOperatorsChecker : FirTypeOperatorCallChecker(MppCheckerKind.Commo
*/ */
private enum class Applicability { private enum class Applicability {
APPLICABLE, APPLICABLE,
IMPOSSIBLE, IMPOSSIBLE_CAST,
IMPOSSIBLE_IS_CHECK,
USELESS_CAST, USELESS_CAST,
USELESS_IS_CHECK, USELESS_IS_CHECK,
CAST_ERASED, CAST_ERASED,
@@ -112,12 +117,15 @@ object FirCastOperatorsChecker : FirTypeOperatorCallChecker(MppCheckerKind.Commo
context: CheckerContext, context: CheckerContext,
) { ) {
when (applicability) { when (applicability) {
Applicability.IMPOSSIBLE -> getImpossibilityDiagnostic(l, r, context)?.let { Applicability.IMPOSSIBLE_CAST -> getImpossibilityDiagnostic(l, r, context)?.let {
reportOn(expression.source, it, context) reportOn(expression.source, it, context)
} }
Applicability.USELESS_CAST -> getUselessCastDiagnostic(context)?.let { Applicability.USELESS_CAST -> getUselessCastDiagnostic(context)?.let {
reportOn(expression.source, it, context) reportOn(expression.source, it, context)
} }
Applicability.IMPOSSIBLE_IS_CHECK -> reportOn(
expression.source, FirErrors.USELESS_IS_CHECK, expression.operation != FirOperation.IS, context,
)
Applicability.USELESS_IS_CHECK -> reportOn( Applicability.USELESS_IS_CHECK -> reportOn(
expression.source, FirErrors.USELESS_IS_CHECK, expression.operation == FirOperation.IS, context, expression.source, FirErrors.USELESS_IS_CHECK, expression.operation == FirOperation.IS, context,
) )
@@ -68,8 +68,8 @@ fun testIs(x: Any) : Int {
} }
} }
fun testIs2(x: lib.FwdStruct) = <!CANNOT_CHECK_FOR_FORWARD_DECLARATION!>x is cnames.structs.FwdStruct<!> fun testIs2(x: lib.FwdStruct) = <!CANNOT_CHECK_FOR_FORWARD_DECLARATION, USELESS_IS_CHECK!>x is cnames.structs.FwdStruct<!>
fun testIs3(x: lib.FwdObjcClass) = <!CANNOT_CHECK_FOR_FORWARD_DECLARATION!>x is objcnames.classes.FwdObjcClass<!> fun testIs3(x: lib.FwdObjcClass) = <!CANNOT_CHECK_FOR_FORWARD_DECLARATION, USELESS_IS_CHECK!>x is objcnames.classes.FwdObjcClass<!>
fun testIs4(x: lib.FwdProtocol) = <!CANNOT_CHECK_FOR_FORWARD_DECLARATION!>x is objcnames.protocols.FwdProtocol<!> fun testIs4(x: lib.FwdProtocol) = <!CANNOT_CHECK_FOR_FORWARD_DECLARATION!>x is objcnames.protocols.FwdProtocol<!>
+1 -1
View File
@@ -2,7 +2,7 @@
fun test() { fun test() {
if (<!USELESS_IS_CHECK!>1 is Int<!>) { if (<!USELESS_IS_CHECK!>1 is Int<!>) {
if (1 is Boolean) { if (<!USELESS_IS_CHECK!>1 is Boolean<!>) {
} }
} }
@@ -19,7 +19,7 @@ fun main() {
<!NO_COMPANION_OBJECT!>System<!>!! <!NO_COMPANION_OBJECT!>System<!>!!
java.lang.<!NO_COMPANION_OBJECT, VARIABLE_EXPECTED!>System<!> = <!NULL_FOR_NONNULL_TYPE!>null<!> java.lang.<!NO_COMPANION_OBJECT, VARIABLE_EXPECTED!>System<!> = <!NULL_FOR_NONNULL_TYPE!>null<!>
java.lang.<!NO_COMPANION_OBJECT!>System<!>!! java.lang.<!NO_COMPANION_OBJECT!>System<!>!!
<!NO_COMPANION_OBJECT!>System<!> is Int <!USELESS_IS_CHECK!><!NO_COMPANION_OBJECT!>System<!> is Int<!>
<!INVISIBLE_REFERENCE!>System<!>() <!INVISIBLE_REFERENCE!>System<!>()
(<!NO_COMPANION_OBJECT!>System<!>) (<!NO_COMPANION_OBJECT!>System<!>)
foo@ <!NO_COMPANION_OBJECT!>System<!> foo@ <!NO_COMPANION_OBJECT!>System<!>
@@ -0,0 +1,4 @@
class G<T>
interface Tr
fun f(q: Tr) = <!USELESS_IS_CHECK!>q is G<*><!>
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
class G<T> class G<T>
interface Tr interface Tr
@@ -11,7 +11,7 @@ fun foo() =
<!CONDITION_TYPE_MISMATCH, TYPE_MISMATCH!>Pair(1, 2)<!> -> 3 <!CONDITION_TYPE_MISMATCH, TYPE_MISMATCH!>Pair(1, 2)<!> -> 3
<!ARGUMENT_TYPE_MISMATCH, EXPECTED_CONDITION!>in 1..10<!> -> 34 <!ARGUMENT_TYPE_MISMATCH, EXPECTED_CONDITION!>in 1..10<!> -> 34
<!CONDITION_TYPE_MISMATCH!>4<!> -> 38 <!CONDITION_TYPE_MISMATCH!>4<!> -> 38
<!EXPECTED_CONDITION!>is Int<!> -> 33 <!EXPECTED_CONDITION, USELESS_IS_CHECK!>is Int<!> -> 33
else -> 34 else -> 34
} }
@@ -9,7 +9,7 @@ class C() {
fun test(a : Any?) { fun test(a : Any?) {
if (a is B) { if (a is B) {
if (a is C) { if (<!USELESS_IS_CHECK!>a is C<!>) {
a.bar(); a.bar();
} }
} }
@@ -30,7 +30,7 @@ fun useEn(x: En) = x
fun useEn2(x: En2) = x fun useEn2(x: En2) = x
fun bar(x: Any) { fun bar(x: Any) {
if (x is En && x is En2) { if (x is En && <!USELESS_IS_CHECK!>x is En2<!>) {
when (x) { when (x) {
En.A -> useEn(x) En.A -> useEn(x)
En2.D -> useEn2(x) En2.D -> useEn2(x)
@@ -5,7 +5,7 @@ interface Entity<T>
abstract class SecuredEntity<out E>(val entity: E) where E : Entity<Int>, E : SecurityCodeAware<*,*> abstract class SecuredEntity<out E>(val entity: E) where E : Entity<Int>, E : SecurityCodeAware<*,*>
interface SecurityCodeAware<out E, R : SecuredEntity<E>> where E : Entity<Int>, E : SecurityCodeAware<E, R> interface SecurityCodeAware<out E, R : SecuredEntity<E>> where E : Entity<Int>, E : SecurityCodeAware<E, R>
fun <E, R : SecuredEntity<E>> SecurityCodeAware<E, R>.secured() : R where E : Entity<Int>, E : SecurityCodeAware<E, R> = <!RETURN_TYPE_MISMATCH!>when(this) { fun <E, R : SecuredEntity<E>> SecurityCodeAware<E, R>.secured() : R where E : Entity<Int>, E : SecurityCodeAware<E, R> = <!RETURN_TYPE_MISMATCH!>when(this) {
is Order -> SecuredOrder(this) <!USELESS_IS_CHECK!>is Order<!> -> SecuredOrder(this)
else -> null!! else -> null!!
}<!> }<!>
class Order : Entity<Int> class Order : Entity<Int>
@@ -45,7 +45,7 @@ fun test(i: Inv<Nothing>, iUnit: Inv<Unit>) {
run<dynamic> { "" } run<dynamic> { "" }
} }
if (iUnit is String) { if (<!USELESS_IS_CHECK!>iUnit is String<!>) {
launch { launch {
run(A.<!INFERRED_TYPE_VARIABLE_INTO_EMPTY_INTERSECTION_WARNING!>flexible<!>(iUnit)) { 42 } run(A.<!INFERRED_TYPE_VARIABLE_INTO_EMPTY_INTERSECTION_WARNING!>flexible<!>(iUnit)) { 42 }
} }
@@ -111,12 +111,12 @@ fun f13(a : A?) {
<!UNRESOLVED_REFERENCE!>c<!>.bar() <!UNRESOLVED_REFERENCE!>c<!>.bar()
} }
if (!(a is B) || !(a is C)) { if (!(a is B) || !(<!USELESS_IS_CHECK!>a is C<!>)) {
} }
else { else {
} }
if (!(a is B) || !(a is C)) { if (!(a is B) || !(<!USELESS_IS_CHECK!>a is C<!>)) {
} }
if (!(a is B)) return if (!(a is B)) return
@@ -11,7 +11,7 @@ class C() {
fun test(a : Any?) { fun test(a : Any?) {
if (a is B) { if (a is B) {
if (a is C) { if (<!USELESS_IS_CHECK!>a is C<!>) {
a.bar(); a.bar();
} }
} }
@@ -0,0 +1,17 @@
sealed class Sealed(val x: Int) {
object First: Sealed(12)
open class NonFirst(x: Int, val y: Int): Sealed(x) {
object Second: NonFirst(34, 2)
object Third: NonFirst(56, 3)
}
object Last: Sealed(78)
}
fun foo(s: Sealed): Int {
return when(s) {
!is Sealed.First -> 1
<!USELESS_IS_CHECK!>!is Sealed.Last<!> -> 0
// no else required
}
}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
sealed class Sealed(val x: Int) { sealed class Sealed(val x: Int) {
object First: Sealed(12) object First: Sealed(12)
open class NonFirst(x: Int, val y: Int): Sealed(x) { open class NonFirst(x: Int, val y: Int): Sealed(x) {
@@ -11,7 +11,7 @@ fun foo(a: A) {
if (a is B) { if (a is B) {
if (a is C) { if (a is C) {
val t = when (a) { val t = when (a) {
is CC -> "CC" <!USELESS_IS_CHECK!>is CC<!> -> "CC"
} }
} }
} }
@@ -21,7 +21,7 @@ fun foo2(a: A) {
if (a is C) { if (a is C) {
if (a is B) { if (a is B) {
val t = when (a) { val t = when (a) {
is CC -> "CC" <!USELESS_IS_CHECK!>is CC<!> -> "CC"
} }
} }
} }
@@ -25,7 +25,7 @@ fun test() {
b.<!UNRESOLVED_REFERENCE!>length<!> // error b.<!UNRESOLVED_REFERENCE!>length<!> // error
c.length // OK, since `c` is aliased to `a` c.length // OK, since `c` is aliased to `a`
} }
if (b is String) { if (<!USELESS_IS_CHECK!>b is String<!>) {
a.<!UNRESOLVED_REFERENCE!>length<!> // error a.<!UNRESOLVED_REFERENCE!>length<!> // error
c.<!UNRESOLVED_REFERENCE!>length<!> // error c.<!UNRESOLVED_REFERENCE!>length<!> // error
} }
@@ -35,11 +35,11 @@ fun test() {
} }
a = 2 // break `c` -> `a` a = 2 // break `c` -> `a`
if (a is String) { if (<!USELESS_IS_CHECK!>a is String<!>) {
b.<!UNRESOLVED_REFERENCE!>length<!> // error b.<!UNRESOLVED_REFERENCE!>length<!> // error
c.<!UNRESOLVED_REFERENCE!>length<!> // error c.<!UNRESOLVED_REFERENCE!>length<!> // error
} }
if (b is String) { if (<!USELESS_IS_CHECK!>b is String<!>) {
a.<!UNRESOLVED_REFERENCE!>length<!> // error a.<!UNRESOLVED_REFERENCE!>length<!> // error
c.<!UNRESOLVED_REFERENCE!>length<!> // error c.<!UNRESOLVED_REFERENCE!>length<!> // error
} }
@@ -11,7 +11,7 @@ fun checkCannotAccess() {
object : InlineCompletionSessionManager() { object : InlineCompletionSessionManager() {
fun chch() { fun chch() {
val b: Proto = Proto() val b: Proto = Proto()
if (b is Proto.Some) return if (<!USELESS_IS_CHECK!>b is Proto.Some<!>) return
} }
} }
} }
+1 -1
View File
@@ -18,7 +18,7 @@ fun foo() : Int {
val s = "" val s = ""
val x = 1 val x = 1
when (x) { when (x) {
is String -> 1 <!USELESS_IS_CHECK!>is String<!> -> 1
<!USELESS_IS_CHECK!>!is Int<!> -> 1 <!USELESS_IS_CHECK!>!is Int<!> -> 1
<!USELESS_IS_CHECK!>is Any?<!> -> 1 <!USELESS_IS_CHECK!>is Any?<!> -> 1
<!USELESS_IS_CHECK!>is Any<!> -> 1 <!USELESS_IS_CHECK!>is Any<!> -> 1
@@ -39,8 +39,8 @@ fun testWithSubject_ok(x: Boolean, y: Boolean?, any: Any, z: Boolean) {
y ?: x -> {} y ?: x -> {}
x in x -> {} x in x -> {}
x !in x -> {} x !in x -> {}
x is String -> {} <!USELESS_IS_CHECK!>x is String<!> -> {}
x !is String -> {} <!USELESS_IS_CHECK!>x !is String<!> -> {}
x < x -> {} x < x -> {}
x > x -> {} x > x -> {}
x <= x -> {} x <= x -> {}
@@ -57,8 +57,8 @@ fun testWithSubject_bad_1(x: A) {
when (x) { when (x) {
<!CONFUSING_BRANCH_CONDITION_ERROR!>x in x<!> -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x in x<!> -> {}
<!CONFUSING_BRANCH_CONDITION_ERROR!>x !in x<!> -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x !in x<!> -> {}
<!CONFUSING_BRANCH_CONDITION_ERROR!>x is String<!> -> {} <!CONFUSING_BRANCH_CONDITION_ERROR, USELESS_IS_CHECK!>x is String<!> -> {}
<!CONFUSING_BRANCH_CONDITION_ERROR!>x !is String<!> -> {} <!CONFUSING_BRANCH_CONDITION_ERROR, USELESS_IS_CHECK!>x !is String<!> -> {}
<!CONFUSING_BRANCH_CONDITION_ERROR!>x < x<!> -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x < x<!> -> {}
<!CONFUSING_BRANCH_CONDITION_ERROR!>x > x<!> -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x > x<!> -> {}
<!CONFUSING_BRANCH_CONDITION_ERROR!>x <= x<!> -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x <= x<!> -> {}
@@ -72,8 +72,8 @@ fun testWithSubject_bad_1(x: A) {
when (x) { when (x) {
(x in x) -> {} (x in x) -> {}
(x !in x) -> {} (x !in x) -> {}
(x is String) -> {} (<!USELESS_IS_CHECK!>x is String<!>) -> {}
(x !is String) -> {} (<!USELESS_IS_CHECK!>x !is String<!>) -> {}
(x < x) -> {} (x < x) -> {}
(x > x) -> {} (x > x) -> {}
(x <= x) -> {} (x <= x) -> {}
@@ -161,8 +161,8 @@ fun testWithRange_bad_1(x: A) {
when (x) { when (x) {
in <!CONFUSING_BRANCH_CONDITION_ERROR!>x in x<!> -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x in x<!> -> {}
in <!CONFUSING_BRANCH_CONDITION_ERROR!>x !in x<!> -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x !in x<!> -> {}
in <!CONFUSING_BRANCH_CONDITION_ERROR!>x is String<!> -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR, USELESS_IS_CHECK!>x is String<!> -> {}
in <!CONFUSING_BRANCH_CONDITION_ERROR!>x !is String<!> -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR, USELESS_IS_CHECK!>x !is String<!> -> {}
in <!CONFUSING_BRANCH_CONDITION_ERROR!>x < x<!> -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x < x<!> -> {}
in <!CONFUSING_BRANCH_CONDITION_ERROR!>x > x<!> -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x > x<!> -> {}
in <!CONFUSING_BRANCH_CONDITION_ERROR!>x <= x<!> -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x <= x<!> -> {}
@@ -176,8 +176,8 @@ fun testWithRange_bad_1(x: A) {
when (x) { when (x) {
in (x in x) -> {} in (x in x) -> {}
in (x !in x) -> {} in (x !in x) -> {}
in (x is String) -> {} in (<!USELESS_IS_CHECK!>x is String<!>) -> {}
in (x !is String) -> {} in (<!USELESS_IS_CHECK!>x !is String<!>) -> {}
in (x < x) -> {} in (x < x) -> {}
in (x > x) -> {} in (x > x) -> {}
in (x <= x) -> {} in (x <= x) -> {}
@@ -57,8 +57,8 @@ fun testWithSubject_bad_1(x: A) {
when (x) { when (x) {
<!CONFUSING_BRANCH_CONDITION_WARNING!>x in x<!> -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x in x<!> -> {}
<!CONFUSING_BRANCH_CONDITION_WARNING!>x !in x<!> -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x !in x<!> -> {}
<!CONFUSING_BRANCH_CONDITION_WARNING!>x is String<!> -> {} <!CONFUSING_BRANCH_CONDITION_WARNING, USELESS_IS_CHECK!>x is String<!> -> {}
<!CONFUSING_BRANCH_CONDITION_WARNING!>x !is String<!> -> {} <!CONFUSING_BRANCH_CONDITION_WARNING, USELESS_IS_CHECK!>x !is String<!> -> {}
<!CONFUSING_BRANCH_CONDITION_WARNING!>x < x<!> -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x < x<!> -> {}
<!CONFUSING_BRANCH_CONDITION_WARNING!>x > x<!> -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x > x<!> -> {}
<!CONFUSING_BRANCH_CONDITION_WARNING!>x <= x<!> -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x <= x<!> -> {}
@@ -72,8 +72,8 @@ fun testWithSubject_bad_1(x: A) {
when (x) { when (x) {
(x in x) -> {} (x in x) -> {}
(x !in x) -> {} (x !in x) -> {}
(x is String) -> {} (<!USELESS_IS_CHECK!>x is String<!>) -> {}
(x !is String) -> {} (<!USELESS_IS_CHECK!>x !is String<!>) -> {}
(x < x) -> {} (x < x) -> {}
(x > x) -> {} (x > x) -> {}
(x <= x) -> {} (x <= x) -> {}
@@ -161,8 +161,8 @@ fun testWithRange_bad_1(x: A) {
when (x) { when (x) {
in <!CONFUSING_BRANCH_CONDITION_WARNING!>x in x<!> -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x in x<!> -> {}
in <!CONFUSING_BRANCH_CONDITION_WARNING!>x !in x<!> -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x !in x<!> -> {}
in <!CONFUSING_BRANCH_CONDITION_WARNING!>x is String<!> -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING, USELESS_IS_CHECK!>x is String<!> -> {}
in <!CONFUSING_BRANCH_CONDITION_WARNING!>x !is String<!> -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING, USELESS_IS_CHECK!>x !is String<!> -> {}
in <!CONFUSING_BRANCH_CONDITION_WARNING!>x < x<!> -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x < x<!> -> {}
in <!CONFUSING_BRANCH_CONDITION_WARNING!>x > x<!> -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x > x<!> -> {}
in <!CONFUSING_BRANCH_CONDITION_WARNING!>x <= x<!> -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x <= x<!> -> {}
@@ -176,8 +176,8 @@ fun testWithRange_bad_1(x: A) {
when (x) { when (x) {
in (x in x) -> {} in (x in x) -> {}
in (x !in x) -> {} in (x !in x) -> {}
in (x is String) -> {} in (<!USELESS_IS_CHECK!>x is String<!>) -> {}
in (x !is String) -> {} in (<!USELESS_IS_CHECK!>x !is String<!>) -> {}
in (x < x) -> {} in (x < x) -> {}
in (x > x) -> {} in (x > x) -> {}
in (x <= x) -> {} in (x <= x) -> {}
@@ -14,29 +14,29 @@ fun foo(a: A) {
if (a !is B) return if (a !is B) return
when (a) { when (a) {
is A.A1 -> "" <!USELESS_IS_CHECK!>is A.A1<!> -> ""
is A.A2 -> "v" <!USELESS_IS_CHECK!>is A.A2<!> -> "v"
}.length }.length
when (a) { when (a) {
is A.A1 -> "" <!USELESS_IS_CHECK!>is A.A1<!> -> ""
is A.A2 -> "v" <!USELESS_IS_CHECK!>is A.A2<!> -> "v"
}.length // OK }.length // OK
when (a) { when (a) {
is A.A1 -> "" <!USELESS_IS_CHECK!>is A.A1<!> -> ""
is A.A2 -> "v" <!USELESS_IS_CHECK!>is A.A2<!> -> "v"
is B.B1 -> "..." // should be warning: unreachable code <!USELESS_IS_CHECK!>is B.B1<!> -> "..." // should be warning: unreachable code
}.length // OK }.length // OK
when (a) { when (a) {
is A.A1 -> "" <!USELESS_IS_CHECK!>is A.A1<!> -> ""
is B.B1 -> "..." <!USELESS_IS_CHECK!>is B.B1<!> -> "..."
is A.A2 -> "v" <!USELESS_IS_CHECK!>is A.A2<!> -> "v"
}.length // OK }.length // OK
<!NO_ELSE_IN_WHEN!>when<!> (a) { <!NO_ELSE_IN_WHEN!>when<!> (a) {
is A.A1 -> "" <!USELESS_IS_CHECK!>is A.A1<!> -> ""
is B.B1 -> "..." <!USELESS_IS_CHECK!>is B.B1<!> -> "..."
}.length }.length
} }
@@ -1,5 +1,5 @@
// SKIP_TXT
// FIR_IDENTICAL // FIR_IDENTICAL
// SKIP_TXT
// !CHECK_TYPE // !CHECK_TYPE
sealed class KtClassifierSymbol sealed class KtClassifierSymbol
@@ -12,7 +12,7 @@ fun testSimpleValInWhenSubject() {
fun testValWithoutInitializerWhenSubject() { fun testValWithoutInitializerWhenSubject() {
when (<!ILLEGAL_DECLARATION_IN_WHEN_SUBJECT!>val y: Any<!>) { when (<!ILLEGAL_DECLARATION_IN_WHEN_SUBJECT!>val y: Any<!>) {
<!EXPECTED_CONDITION!>is String<!> -> <!UNINITIALIZED_VARIABLE!>y<!>.<!UNRESOLVED_REFERENCE!>length<!> <!EXPECTED_CONDITION, USELESS_IS_CHECK!>is String<!> -> <!UNINITIALIZED_VARIABLE!>y<!>.<!UNRESOLVED_REFERENCE!>length<!>
} }
} }
@@ -79,7 +79,7 @@ fun branchedAndNested(x: Any?, y: Any?) {
fun br(y: Any?) { fun br(y: Any?) {
if (myAssert(y is Int) == Unit && myAssert(y is String) == Unit) { if (myAssert(y is Int) == Unit && myAssert(<!USELESS_IS_CHECK!>y is String<!>) == Unit) {
y.length y.length
y.inc() y.inc()
} }
@@ -90,7 +90,7 @@ fun branchedAndNestedWithNativeOperators(x: Any?, y: Any?) {
equalsTrue(notEqualsNull(nullWhenNotString(x))) // x is String equalsTrue(notEqualsNull(nullWhenNotString(x))) // x is String
&& &&
( (
(myAssert(y is Int) == Unit && myAssert(y is String) == Unit) // y is Int, String (myAssert(y is Int) == Unit && myAssert(<!USELESS_IS_CHECK!>y is String<!>) == Unit) // y is Int, String
|| ||
equalsTrue(isInt(y) && isString(y)) // y is Int, String equalsTrue(isInt(y) && isString(y)) // y is Int, String
) )
@@ -45,8 +45,8 @@ fun intersectingInfo2(x: Any?, y: Any?) {
// of them is absent in each arg of "||"-operator, so they *shouldn't* lead to smartcast // of them is absent in each arg of "||"-operator, so they *shouldn't* lead to smartcast
if ((isString(x) && !notIsInt(x) && y is String) || if ((isString(x) && !notIsInt(x) && y is String) ||
(!notIsString(x) && isString(y) && y is Int) || (!notIsString(x) && isString(y) && <!USELESS_IS_CHECK!>y is Int<!>) ||
(x is String && !notIsInt(y) && x is Int)) { (x is String && !notIsInt(y) && <!USELESS_IS_CHECK!>x is Int<!>)) {
x.length x.length
x.<!UNRESOLVED_REFERENCE!>inc<!>() x.<!UNRESOLVED_REFERENCE!>inc<!>()
y.<!UNRESOLVED_REFERENCE!>length<!> y.<!UNRESOLVED_REFERENCE!>length<!>
@@ -14,8 +14,8 @@
// TESTCASE NUMBER: 1 // TESTCASE NUMBER: 1
fun case_1(value_1: SealedClass) = when (value_1) { fun case_1(value_1: SealedClass) = when (value_1) {
!is SealedChild1 -> {} !is SealedChild1 -> {}
!is SealedChild2 -> {} <!USELESS_IS_CHECK!>!is SealedChild2<!> -> {}
!is SealedChild3 -> {} <!USELESS_IS_CHECK!>!is SealedChild3<!> -> {}
} }
/* /*
@@ -18,7 +18,7 @@ fun case_1(value_1: SealedClass): String = when (value_1) {
// TESTCASE NUMBER: 2 // TESTCASE NUMBER: 2
fun case_2(value_1: SealedClass) = when (value_1) { fun case_2(value_1: SealedClass) = when (value_1) {
!is SealedChild1, !is SealedChild2, !is SealedChild3 -> {} !is SealedChild1, <!USELESS_IS_CHECK!>!is SealedChild2<!>, <!USELESS_IS_CHECK!>!is SealedChild3<!> -> {}
} }
// TESTCASE NUMBER: 3 // TESTCASE NUMBER: 3
@@ -107,7 +107,7 @@ fun case_8(value_1: Any?) {
// TESTCASE NUMBER: 9 // TESTCASE NUMBER: 9
fun case_9(value_1: Any?) { fun case_9(value_1: Any?) {
if (funWithReturnsFalse(value_1 is String) || funWithReturnsFalse(value_1 is Int)) { if (funWithReturnsFalse(value_1 is String) || funWithReturnsFalse(<!USELESS_IS_CHECK!>value_1 is Int<!>)) {
} else { } else {
println(value_1.length) println(value_1.length)
@@ -37,7 +37,7 @@ fun <T> T?.case_3(): Boolean {
// TESTCASE NUMBER: 4 // TESTCASE NUMBER: 4
inline fun <reified T : Number> T.case_4(): Boolean { inline fun <reified T : Number> T.case_4(): Boolean {
contract { contract {
<!ERROR_IN_CONTRACT_DESCRIPTION!>returns(null) implies (this is Int)<!> <!ERROR_IN_CONTRACT_DESCRIPTION!>returns(null) implies (<!USELESS_IS_CHECK!>this is Int<!>)<!>
} }
return this is Int return this is Int
} }
@@ -70,13 +70,13 @@ class case_4 : ClassLevel3() {
class case_5<T> : ClassLevel5() { class case_5<T> : ClassLevel5() {
inner class case_5_1 { inner class case_5_1 {
fun <K : Number?>K.case_5_1_1() { fun <K : Number?>K.case_5_1_1() {
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (this@case_5_1 !is ClassLevel1 && <!SENSELESS_COMPARISON!>this@case_5_1 != null<!> || <!USELESS_IS_CHECK!>this@case_5 is ClassLevel1<!> && this@case_5_1_1 is Float)<!> } contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (<!USELESS_IS_CHECK!>this@case_5_1 !is ClassLevel1<!> && <!SENSELESS_COMPARISON!>this@case_5_1 != null<!> || <!USELESS_IS_CHECK!>this@case_5 is ClassLevel1<!> && this@case_5_1_1 is Float)<!> }
if (!(this@case_5_1 !is ClassLevel1 && <!SENSELESS_COMPARISON!>this@case_5_1 != null<!> || <!USELESS_IS_CHECK!>this@case_5 is ClassLevel1<!> && this is Float)) throw Exception() if (!(<!USELESS_IS_CHECK!>this@case_5_1 !is ClassLevel1<!> && <!SENSELESS_COMPARISON!>this@case_5_1 != null<!> || <!USELESS_IS_CHECK!>this@case_5 is ClassLevel1<!> && this is Float)) throw Exception()
} }
fun case_5_1_2() { fun case_5_1_2() {
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (this@case_5_1 !is ClassLevel1 || <!USELESS_IS_CHECK!>this@case_5 is ClassLevel1<!> || <!SENSELESS_COMPARISON!>this@case_5_1 == null<!>)<!> } contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (<!USELESS_IS_CHECK!>this@case_5_1 !is ClassLevel1<!> || <!USELESS_IS_CHECK!>this@case_5 is ClassLevel1<!> || <!SENSELESS_COMPARISON!>this@case_5_1 == null<!>)<!> }
if (!(this@case_5_1 !is ClassLevel1 || <!USELESS_IS_CHECK!>this@case_5 is ClassLevel1<!> || <!SENSELESS_COMPARISON!>this@case_5_1 == null<!>)) throw Exception() if (!(<!USELESS_IS_CHECK!>this@case_5_1 !is ClassLevel1<!> || <!USELESS_IS_CHECK!>this@case_5 is ClassLevel1<!> || <!SENSELESS_COMPARISON!>this@case_5_1 == null<!>)) throw Exception()
} }
} }
} }
@@ -12,7 +12,7 @@
// TESTCASE NUMBER: 1 // TESTCASE NUMBER: 1
fun <T : List<T>> Inv<out T>.case_1() { fun <T : List<T>> Inv<out T>.case_1() {
if (this is MutableList<*>) { if (<!USELESS_IS_CHECK!>this is MutableList<*><!>) {
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<out T> & kotlin.collections.MutableList<*> & Inv<out T>")!>this<!> <!DEBUG_INFO_EXPRESSION_TYPE("Inv<out T> & kotlin.collections.MutableList<*> & Inv<out T>")!>this<!>
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<out T> & kotlin.collections.MutableList<*> & Inv<out T>")!>this<!>[0] = <!ARGUMENT_TYPE_MISMATCH!><!DEBUG_INFO_EXPRESSION_TYPE("Inv<out T> & kotlin.collections.MutableList<*> & Inv<out T>")!>this<!>[1]<!> <!DEBUG_INFO_EXPRESSION_TYPE("Inv<out T> & kotlin.collections.MutableList<*> & Inv<out T>")!>this<!>[0] = <!ARGUMENT_TYPE_MISMATCH!><!DEBUG_INFO_EXPRESSION_TYPE("Inv<out T> & kotlin.collections.MutableList<*> & Inv<out T>")!>this<!>[1]<!>
} }