[FIR] Utilize equality compatibility logic for cast checks

This makes it more consistent and fixes some
overlooked corner cases. Also it was decided
on the last equality applicability DM
(KT-62646) that we'd like
`is`/`!is`/`as`/`as?` to work similarly
to `===`/`!==`.

Also note that it now gives a clearer
explaination of why some corner cases work
the way they do. For example,
`FirPsiDiagnosticTestGenerated.testLambdaInLhsOfTypeOperatorCall`
yields `UNCHECKED_CAST` instead of
`CAST_NEVER_SUCCEEDS`, because
`toTypeInfo()` replaces all type arguments
with star projections, even when the argument
is not a type parameter. This is because
it has been desided to work this way in
KT-57779.

In
`FirPsiOldFrontendDiagnosticsTestGenerated..NeverSucceeds#testNoGenericsRelated`
the diagnostic is introduced, because
`t2 as FC1` and `FC1` is a final class with
no `T5` supertype.

`UNCHECKED_CAST` in
`FirPsiOldFrontendDiagnosticsTestGenerated.testSmartCast`
disappeared, because previously we didn't
take smartcasts into account.

Note that
`FirPsiOldFrontendDiagnosticsTestGenerated.testMappedSubtypes`
is a false positive. It appears because `isSubtypeOf()` doesn't
take into account platform types in supertypes of the given types
(doesn't map them).
This commit is contained in:
Nikolay Lunyak
2024-02-28 14:17:35 +02:00
committed by Space Team
parent a5e43c9e3f
commit fab6cec93a
25 changed files with 253 additions and 193 deletions
@@ -55,7 +55,7 @@ class Case8<K> {
}
// TESTCASE NUMBER: 9
inline fun <reified L: Nothing?> case_9(x: L) = x!! as Int
inline fun <reified L: Nothing?> case_9(x: L) = x!! <!CAST_NEVER_SUCCEEDS!>as<!> Int
// TESTCASE NUMBER: 10
fun <K> case_10(x: Nothing) = x as Iterable<K>
@@ -44,7 +44,7 @@ fun case_2(x: Int?, y: Nothing?) {
*/
fun case_3(x: Int?) {
if (x == null) {
x as Int
x <!CAST_NEVER_SUCCEEDS!>as<!> Int
stringArg(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int? & kotlin.Nothing")!>x<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int? & kotlin.Nothing")!>x<!>
}
@@ -124,7 +124,7 @@ fun case_10() {
do {
x = null
break
} while ((x as String).length > 1)
} while ((x <!CAST_NEVER_SUCCEEDS!>as<!> String).length > 1)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String? & kotlin.Nothing?")!>x<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String? & kotlin.Nothing?")!>x<!><!UNSAFE_CALL!>.<!>length
}
@@ -106,10 +106,10 @@ fun case_6() {
val e: Any?
when (if (true) {b = 11} else {b = 12}) {
when (if (true) {b.inv(); c = b; c as ClassLevel1;} else {b.inv(); c = b; c as ClassLevel1;}) {
when (if (true) {b.inv(); c = b; c <!CAST_NEVER_SUCCEEDS!>as<!> ClassLevel1;} else {b.inv(); c = b; c <!CAST_NEVER_SUCCEEDS!>as<!> ClassLevel1;}) {
else -> kotlin.Unit
} -> when (if (true) {c.test1(); d = c; d as ClassLevel2} else {c.test1(); d = c; d as ClassLevel2}) {
when (if (true) {d.test2(); e = d; e as ClassLevel3} else {d.test2(); e = d; e as ClassLevel3}) {
} -> when (if (true) {c.test1(); d = c; d <!CAST_NEVER_SUCCEEDS!>as<!> ClassLevel2} else {c.test1(); d = c; d <!CAST_NEVER_SUCCEEDS!>as<!> ClassLevel2}) {
when (if (true) {d.test2(); e = d; e <!CAST_NEVER_SUCCEEDS!>as<!> ClassLevel3} else {d.test2(); e = d; e <!CAST_NEVER_SUCCEEDS!>as<!> ClassLevel3}) {
else -> ClassLevel2()
} -> {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & kotlin.Int & ClassLevel3")!>e<!>
@@ -140,7 +140,7 @@ fun case_11(z: Any?, x: Any?) {
fun case_12(z: Any?) {
val y = z.let {
return@let it as Int
it as? Float ?: 10f
it <!CAST_NEVER_SUCCEEDS!>as?<!> Float ?: 10f
}
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number & kotlin.Comparable<*>")!>y<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number & kotlin.Comparable<*>")!>y<!>.toByte()
@@ -164,7 +164,7 @@ fun case_13(z: Any?) {
fun case_14(z: Any?) {
val y = z.run {
return@run this as Int
this as? Float ?: 10f
this <!CAST_NEVER_SUCCEEDS!>as?<!> Float ?: 10f
}
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number & kotlin.Comparable<*>")!>y<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number & kotlin.Comparable<*>")!>y<!>.toByte()