fab6cec93a
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).
69 lines
1.8 KiB
Kotlin
Vendored
69 lines
1.8 KiB
Kotlin
Vendored
// ISSUE: KT-56744
|
|
// !LANGUAGE: +SafeCastCheckBoundSmartCasts
|
|
interface SomeClass {
|
|
val data: Any?
|
|
}
|
|
|
|
interface SomeSubClass : SomeClass {
|
|
val foo: Any?
|
|
}
|
|
|
|
object Impl : SomeSubClass {
|
|
override val data = ""
|
|
override val foo = 42
|
|
}
|
|
|
|
fun g(a: SomeClass?) {
|
|
var b = (a as? SomeSubClass)?.foo
|
|
b = "Hello"
|
|
if (<!SENSELESS_COMPARISON!>b != null<!>) {
|
|
// 'a' cannot be cast to SomeSubClass!
|
|
a<!UNSAFE_CALL!>.<!>hashCode()
|
|
a.<!UNRESOLVED_REFERENCE!>foo<!>
|
|
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
|
(a as SomeSubClass).foo
|
|
}
|
|
var c = a as? SomeSubClass
|
|
c = Impl
|
|
if (<!SENSELESS_COMPARISON!>c != null<!>) {
|
|
// 'a' cannot be cast to SomeSubClass
|
|
a<!UNSAFE_CALL!>.<!>hashCode()
|
|
a.<!UNRESOLVED_REFERENCE!>foo<!>
|
|
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
|
c.hashCode()
|
|
c.foo
|
|
}
|
|
}
|
|
|
|
fun f(a: SomeClass?) {
|
|
var aa = a
|
|
|
|
if (aa as? SomeSubClass != null) {
|
|
aa = null
|
|
// 'aa' cannot be cast to SomeSubClass
|
|
aa<!UNSAFE_CALL!>.<!>hashCode()
|
|
aa.<!UNRESOLVED_REFERENCE!>foo<!>
|
|
(aa <!USELESS_CAST!>as? SomeSubClass<!>)<!UNSAFE_CALL!>.<!>foo
|
|
(aa <!CAST_NEVER_SUCCEEDS!>as<!> SomeSubClass).foo
|
|
}
|
|
val b = (aa as? SomeSubClass)?.foo
|
|
aa = null
|
|
if (b != null) {
|
|
// 'aa' cannot be cast to SomeSubClass
|
|
aa<!UNSAFE_CALL!>.<!>hashCode()
|
|
aa.<!UNRESOLVED_REFERENCE!>foo<!>
|
|
(aa <!USELESS_CAST!>as? SomeSubClass<!>)<!UNSAFE_CALL!>.<!>foo
|
|
(aa <!CAST_NEVER_SUCCEEDS!>as<!> SomeSubClass).foo
|
|
}
|
|
aa = a
|
|
val c = aa as? SomeSubClass
|
|
if (c != null) {
|
|
// 'c' can be cast to SomeSubClass
|
|
aa.hashCode()
|
|
aa.foo
|
|
(aa <!USELESS_CAST!>as? SomeSubClass<!>)<!UNSAFE_CALL!>.<!>foo
|
|
c.hashCode()
|
|
c.foo
|
|
}
|
|
}
|