Support smart casts to Type after x as? Type null check #KT-4565 Fixed

This commit is contained in:
Mikhail Glukhikh
2017-08-10 15:47:59 +03:00
parent 5bd04a6d22
commit 80b6aaa802
14 changed files with 318 additions and 22 deletions
@@ -0,0 +1,36 @@
// !LANGUAGE: -SafeCastCheckBoundSmartCasts
interface SomeClass {
val data: Any?
}
interface SomeSubClass : SomeClass {
val foo: Any?
}
fun g(a: SomeClass?) {
if (a as? SomeSubClass != null) {
// 'a' can be cast to SomeSubClass
a<!UNSAFE_CALL!>.<!>hashCode()
a.<!UNRESOLVED_REFERENCE!>foo<!>
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
(a as SomeSubClass).foo
}
val b = (a as? SomeSubClass)?.foo
if (b != null) {
// 'a' can be cast to SomeSubClass
a<!UNSAFE_CALL!>.<!>hashCode()
a.<!UNRESOLVED_REFERENCE!>foo<!>
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
(a as SomeSubClass).foo
}
val c = a as? SomeSubClass
if (c != null) {
// 'a' and 'c' can be cast to SomeSubClass
a<!UNSAFE_CALL!>.<!>hashCode()
a.<!UNRESOLVED_REFERENCE!>foo<!>
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
<!DEBUG_INFO_SMARTCAST!>c<!>.hashCode()
<!DEBUG_INFO_SMARTCAST!>c<!>.foo
}
}
@@ -0,0 +1,18 @@
package
public fun g(/*0*/ a: SomeClass?): kotlin.Unit
public interface SomeClass {
public abstract val data: kotlin.Any?
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface SomeSubClass : SomeClass {
public abstract override /*1*/ /*fake_override*/ val data: kotlin.Any?
public abstract val foo: kotlin.Any?
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,36 @@
// !LANGUAGE: +SafeCastCheckBoundSmartCasts
interface SomeClass {
val data: Any?
}
interface SomeSubClass : SomeClass {
val foo: Any?
}
fun g(a: SomeClass?) {
if (a as? SomeSubClass != null) {
// 'a' can be cast to SomeSubClass
<!DEBUG_INFO_SMARTCAST!>a<!>.hashCode()
<!DEBUG_INFO_SMARTCAST!>a<!>.foo
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
(a <!USELESS_CAST!>as SomeSubClass<!>).foo
}
val b = (a as? SomeSubClass)?.foo
if (b != null) {
// 'a' can be cast to SomeSubClass
<!DEBUG_INFO_SMARTCAST!>a<!>.hashCode()
<!DEBUG_INFO_SMARTCAST!>a<!>.foo
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
(a <!USELESS_CAST!>as SomeSubClass<!>).foo
}
val c = a as? SomeSubClass
if (c != null) {
// 'a' and 'c' can be cast to SomeSubClass
<!DEBUG_INFO_SMARTCAST!>a<!>.hashCode()
<!DEBUG_INFO_SMARTCAST!>a<!>.foo
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
<!DEBUG_INFO_SMARTCAST!>c<!>.hashCode()
<!DEBUG_INFO_SMARTCAST!>c<!>.foo
}
}
@@ -0,0 +1,18 @@
package
public fun g(/*0*/ a: SomeClass?): kotlin.Unit
public interface SomeClass {
public abstract val data: kotlin.Any?
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface SomeSubClass : SomeClass {
public abstract override /*1*/ /*fake_override*/ val data: kotlin.Any?
public abstract val foo: kotlin.Any?
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,13 @@
// !LANGUAGE: +SafeCastCheckBoundSmartCasts
// See KT-19007
// Stub
fun String.indexOf(arg: String) = this.length - arg.length
// Stub
fun String.toLowerCase() = this
fun foo(a: Any) {
// Should compile in 1.2
(a as? String)?.indexOf(<!DEBUG_INFO_SMARTCAST!>a<!>.toLowerCase())
}
@@ -0,0 +1,5 @@
package
public fun foo(/*0*/ a: kotlin.Any): kotlin.Unit
public fun kotlin.String.indexOf(/*0*/ arg: kotlin.String): kotlin.Int
public fun kotlin.String.toLowerCase(): kotlin.String
@@ -0,0 +1,67 @@
// !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 = <!VARIABLE_WITH_REDUNDANT_INITIALIZER!>(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 = <!VARIABLE_WITH_REDUNDANT_INITIALIZER!>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
<!DEBUG_INFO_SMARTCAST!>c<!>.hashCode()
<!DEBUG_INFO_SMARTCAST!>c<!>.foo
}
}
fun f(a: SomeClass?) {
var aa = a
if (aa as? SomeSubClass != null) {
aa = null
// 'aa' cannot be cast to SomeSubClass
<!DEBUG_INFO_CONSTANT!>aa<!><!UNSAFE_CALL!>.<!>hashCode()
aa.<!UNRESOLVED_REFERENCE!>foo<!>
(<!DEBUG_INFO_CONSTANT!>aa<!> as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
(<!ALWAYS_NULL!>aa<!> as SomeSubClass).foo
}
val b = (aa as? SomeSubClass)?.foo
aa = null
if (b != null) {
// 'aa' cannot be cast to SomeSubClass
<!DEBUG_INFO_CONSTANT!>aa<!><!UNSAFE_CALL!>.<!>hashCode()
aa.<!UNRESOLVED_REFERENCE!>foo<!>
(<!DEBUG_INFO_CONSTANT!>aa<!> as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
(<!ALWAYS_NULL!>aa<!> as SomeSubClass).foo
}
aa = a
val c = aa as? SomeSubClass
if (c != null) {
// 'c' can be cast to SomeSubClass
aa<!UNSAFE_CALL!>.<!>hashCode()
aa.<!UNRESOLVED_REFERENCE!>foo<!>
(aa as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
<!DEBUG_INFO_SMARTCAST!>c<!>.hashCode()
<!DEBUG_INFO_SMARTCAST!>c<!>.foo
}
}
@@ -0,0 +1,28 @@
package
public fun f(/*0*/ a: SomeClass?): kotlin.Unit
public fun g(/*0*/ a: SomeClass?): kotlin.Unit
public object Impl : SomeSubClass {
private constructor Impl()
public open override /*1*/ val data: kotlin.String = ""
public open override /*1*/ val foo: kotlin.Int = 42
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface SomeClass {
public abstract val data: kotlin.Any?
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface SomeSubClass : SomeClass {
public abstract override /*1*/ /*fake_override*/ val data: kotlin.Any?
public abstract val foo: kotlin.Any?
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -1,3 +1,4 @@
// !LANGUAGE: -SafeCastCheckBoundSmartCasts
// A set of examples for
// "If the result of a safe call is not null, understand that its receiver is not null"
// and some other improvements for nullability detection