[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) {
Enum.A -> 1
Enum.B -> 2
is String -> 3
<!USELESS_IS_CHECK!>is String<!> -> 3
}
val c = when (e) {
@@ -15,7 +15,7 @@ fun test_1(e: JavaEnum) {
val b = <!NO_ELSE_IN_WHEN!>when<!> (e) {
JavaEnum.A -> 1
JavaEnum.B -> 2
is String -> 3
<!USELESS_IS_CHECK!>is String<!> -> 3
}.plus(0)
val c = when (e) {
@@ -15,7 +15,7 @@ fun test_1(e: Base) {
val b = <!NO_ELSE_IN_WHEN!>when<!> (e) {
is Base.A -> 1
is Base.A.B -> 2
is String -> 3
<!USELESS_IS_CHECK!>is String<!> -> 3
}
val c = when (e) {
@@ -17,7 +17,7 @@ fun test_2(x: Any) {
fun test_3(x: Any) {
when {
x !is String -> {}
x !is Int -> {}
<!USELESS_IS_CHECK!>x !is Int<!> -> {}
else -> {
x.length
x.inc()
@@ -16,7 +16,7 @@ fun test_1(x: Any?) {
when {
x !is A -> {}
x !is B -> x.foo()
x is Int -> {
<!USELESS_IS_CHECK!>x is Int<!> -> {
x.foo()
x.bar()
x.inc()
@@ -37,7 +37,7 @@ fun test_2(x: Any?) {
when(x) {
!is A -> {}
!is B -> x.foo()
is Int -> {
<!USELESS_IS_CHECK!>is Int<!> -> {
x.foo()
x.bar()
x.inc()
@@ -67,7 +67,7 @@ fun test_3(x: Any?) {
x.foo()
y.foo()
}
is Int -> {
<!USELESS_IS_CHECK!>is Int<!> -> {
x.foo()
x.bar()
x.inc()
@@ -53,7 +53,7 @@ fun Any?.test_4() {
<!UNRESOLVED_REFERENCE!>foo<!>()
this.<!UNRESOLVED_REFERENCE!>bar<!>()
<!UNRESOLVED_REFERENCE!>bar<!>()
} else if (this !is B) {
} else if (<!USELESS_IS_CHECK!>this !is B<!>) {
this.<!UNRESOLVED_REFERENCE!>bar<!>()
<!UNRESOLVED_REFERENCE!>bar<!>()
this.foo()
@@ -13,7 +13,7 @@ fun test1(x: String?): Int? {
@OptIn(ExperimentalContracts::class)
fun test2(x: String?): Int? {
<!WRONG_IMPLIES_CONDITION!>contract {
returnsNotNull() implies (x is Boolean)
returnsNotNull() implies (<!USELESS_IS_CHECK!>x is Boolean<!>)
}<!>
return x?.length
@@ -20,7 +20,7 @@ fun <T> deserializeAndLoadState(
) {}
fun use(beforeRunTask: BeforeRunTask<*>) {
if (beforeRunTask is PersistentStateComponent<*>) {
if (<!USELESS_IS_CHECK!>beforeRunTask is PersistentStateComponent<*><!>) {
deserializeAndLoadState(beforeRunTask)
}
}
@@ -14,5 +14,5 @@ fun foo(u: U) {
val w = +i
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 {
val oneIsFinal = l.isFinal || r.isFinal
val oneIsNotNull = !l.type.isNullable || !r.type.isNullable
return when {
isRefinementUseless(context, l.directType.upperBoundIfFlexible(), r.directType, expression) -> Applicability.USELESS_IS_CHECK
isCastErased(l.directType, r.directType, context) -> Applicability.CAST_ERASED
oneIsNotNull && oneIsFinal && areUnrelated(l, r, context) -> Applicability.IMPOSSIBLE_IS_CHECK
else -> Applicability.APPLICABLE
}
}
@@ -62,13 +66,13 @@ object FirCastOperatorsChecker : FirTypeOperatorCallChecker(MppCheckerKind.Commo
return when {
isRefinementUseless(context, l.directType.upperBoundIfFlexible(), r.directType, expression) -> Applicability.USELESS_CAST
l.type.isNothing && r.type.isNothingOrNullableNothing -> Applicability.APPLICABLE
r.type.isNothing -> Applicability.IMPOSSIBLE
r.type.isNothing -> Applicability.IMPOSSIBLE_CAST
isNullableNothingWithNotNull -> when (expression.operation) {
// (null as? WhatEver) == null
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
else -> Applicability.APPLICABLE
}
@@ -91,7 +95,8 @@ object FirCastOperatorsChecker : FirTypeOperatorCallChecker(MppCheckerKind.Commo
*/
private enum class Applicability {
APPLICABLE,
IMPOSSIBLE,
IMPOSSIBLE_CAST,
IMPOSSIBLE_IS_CHECK,
USELESS_CAST,
USELESS_IS_CHECK,
CAST_ERASED,
@@ -112,12 +117,15 @@ object FirCastOperatorsChecker : FirTypeOperatorCallChecker(MppCheckerKind.Commo
context: CheckerContext,
) {
when (applicability) {
Applicability.IMPOSSIBLE -> getImpossibilityDiagnostic(l, r, context)?.let {
Applicability.IMPOSSIBLE_CAST -> getImpossibilityDiagnostic(l, r, context)?.let {
reportOn(expression.source, it, context)
}
Applicability.USELESS_CAST -> getUselessCastDiagnostic(context)?.let {
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(
expression.source, FirErrors.USELESS_IS_CHECK, expression.operation == FirOperation.IS, context,
)