Smart casts for local variables not captured in a closure and not changed in a loop, see #KT-3175.
isLocalVariable added. Assignment / initialization analysis. Control whether a variable is changed in a loop at the beginning and at the end of the loop. Control whether a variable is captured in a closure. #KT-3175 Fixed. #KT-2266 Fixed. Tests for variable null safety and for variables is/as operations. Loop / closure / variable property tests are included. Old tests changed in accordance with KT-3175. In particular, all three of testSmartcastImpossible were fixed.
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
fun foo() {
|
||||
var v: Any = 42
|
||||
v.<!UNRESOLVED_REFERENCE!>length<!>()
|
||||
v = "abc"
|
||||
<!DEBUG_INFO_SMARTCAST!>v<!>.length()
|
||||
v = 42
|
||||
v.<!UNRESOLVED_REFERENCE!>length<!>()
|
||||
v = "abc"
|
||||
<!DEBUG_INFO_SMARTCAST!>v<!>.length()
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
internal fun foo(): kotlin.Unit
|
||||
@@ -0,0 +1,12 @@
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(pp: Any): Int {
|
||||
var p = pp
|
||||
do {
|
||||
(p as String).length()
|
||||
if (p == "abc") break
|
||||
p = 42
|
||||
} while (!x())
|
||||
// Smart cast is NOT possible here
|
||||
return p.<!UNRESOLVED_REFERENCE!>length<!>()
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
public fun foo(/*0*/ pp: kotlin.Any): kotlin.Int
|
||||
internal fun x(): kotlin.Boolean
|
||||
@@ -0,0 +1,15 @@
|
||||
public fun foo(xx: Any): Int {
|
||||
var x = xx
|
||||
do {
|
||||
var y: Any
|
||||
// After the check, smart cast should work
|
||||
if (x is String) {
|
||||
y = "xyz"
|
||||
} else {
|
||||
y = "abc"
|
||||
}
|
||||
// y!! in both branches
|
||||
<!DEBUG_INFO_SMARTCAST!>y<!>.length()
|
||||
} while (!(x is String))
|
||||
return <!DEBUG_INFO_SMARTCAST!>x<!>.length()
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
public fun foo(/*0*/ xx: kotlin.Any): kotlin.Int
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
public fun foo(xx: Any): Int {
|
||||
var x = xx
|
||||
do {
|
||||
var y: Any
|
||||
// After the check, smart cast should work
|
||||
if (x is String) {
|
||||
break
|
||||
} else {
|
||||
y = "abc"
|
||||
}
|
||||
// y!! in both branches
|
||||
<!DEBUG_INFO_SMARTCAST!>y<!>.length()
|
||||
} while (true)
|
||||
// We could have smart cast here but with break it's hard to detect
|
||||
return x.<!UNRESOLVED_REFERENCE!>length<!>()
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
public fun foo(/*0*/ xx: kotlin.Any): kotlin.Int
|
||||
@@ -0,0 +1,9 @@
|
||||
public fun bar(s: String) {
|
||||
System.out.println("Length of $s is ${s.length()}")
|
||||
}
|
||||
|
||||
public fun foo() {
|
||||
var s: Any = "not null"
|
||||
if (s is String)
|
||||
bar(<!DEBUG_INFO_SMARTCAST!>s<!>)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
public fun bar(/*0*/ s: kotlin.String): kotlin.Unit
|
||||
public fun foo(): kotlin.Unit
|
||||
@@ -0,0 +1,13 @@
|
||||
// See KT-5737
|
||||
fun get(): Any {
|
||||
return "abc"
|
||||
}
|
||||
|
||||
fun foo(): Int {
|
||||
var ss: Any = get()
|
||||
|
||||
return if (ss is String && <!DEBUG_INFO_SMARTCAST!>ss<!>.length() > 0)
|
||||
1
|
||||
else
|
||||
0
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
internal fun foo(): kotlin.Int
|
||||
internal fun get(): kotlin.Any
|
||||
@@ -0,0 +1,11 @@
|
||||
public fun bar(s: String) {
|
||||
System.out.println("Length of $s is ${s.length()}")
|
||||
}
|
||||
|
||||
public fun foo() {
|
||||
var s: Any = "not null"
|
||||
if (s is String) {
|
||||
s = 42
|
||||
bar(<!TYPE_MISMATCH!>s<!>)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
public fun bar(/*0*/ s: kotlin.String): kotlin.Unit
|
||||
public fun foo(): kotlin.Unit
|
||||
@@ -0,0 +1,11 @@
|
||||
// See KT-774
|
||||
fun box() : Int {
|
||||
var a : Any = 1
|
||||
var d = 1
|
||||
|
||||
if (a is Int) {
|
||||
return <!DEBUG_INFO_SMARTCAST!>a<!> + d
|
||||
} else {
|
||||
return 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
internal fun box(): kotlin.Int
|
||||
@@ -0,0 +1,8 @@
|
||||
fun foo() {
|
||||
var v: Any = "xyz"
|
||||
// It is possible in principle to provide smart cast here
|
||||
// but now we decide that v is Any
|
||||
v.<!UNRESOLVED_REFERENCE!>length<!>()
|
||||
v = 42
|
||||
v.<!UNRESOLVED_REFERENCE!>length<!>()
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
internal fun foo(): kotlin.Unit
|
||||
@@ -0,0 +1,10 @@
|
||||
class MyClass(var p: String?)
|
||||
|
||||
fun bar(s: String): Int {
|
||||
return s.length()
|
||||
}
|
||||
|
||||
fun foo(m: MyClass): Int {
|
||||
m.p = "xyz"
|
||||
return bar(<!SMARTCAST_IMPOSSIBLE!>m.p<!>)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package
|
||||
|
||||
internal fun bar(/*0*/ s: kotlin.String): kotlin.Int
|
||||
internal fun foo(/*0*/ m: MyClass): kotlin.Int
|
||||
|
||||
internal final class MyClass {
|
||||
public constructor MyClass(/*0*/ p: kotlin.String?)
|
||||
internal final var p: kotlin.String?
|
||||
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,10 @@
|
||||
class MyClass(var p: String?)
|
||||
|
||||
fun bar(s: String?): Int {
|
||||
return s?.length() ?: -1
|
||||
}
|
||||
|
||||
fun foo(m: MyClass): Int {
|
||||
m.p = "xyz"
|
||||
return bar(m.p)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package
|
||||
|
||||
internal fun bar(/*0*/ s: kotlin.String?): kotlin.Int
|
||||
internal fun foo(/*0*/ m: MyClass): kotlin.Int
|
||||
|
||||
internal final class MyClass {
|
||||
public constructor MyClass(/*0*/ p: kotlin.String?)
|
||||
internal final var p: kotlin.String?
|
||||
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,10 @@
|
||||
class MyClass(var p: Any)
|
||||
|
||||
fun bar(s: Any): Int {
|
||||
return s.hashCode()
|
||||
}
|
||||
|
||||
fun foo(m: MyClass): Int {
|
||||
m.p = "xyz"
|
||||
return bar(m.p)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package
|
||||
|
||||
internal fun bar(/*0*/ s: kotlin.Any): kotlin.Int
|
||||
internal fun foo(/*0*/ m: MyClass): kotlin.Int
|
||||
|
||||
internal final class MyClass {
|
||||
public constructor MyClass(/*0*/ p: kotlin.Any)
|
||||
internal final var p: 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,10 @@
|
||||
fun bar(s: Any): Int {
|
||||
return s.hashCode()
|
||||
}
|
||||
|
||||
class MyClass(var p: Any) {
|
||||
fun foo(): Int {
|
||||
p = "xyz"
|
||||
return bar(p)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package
|
||||
|
||||
internal fun bar(/*0*/ s: kotlin.Any): kotlin.Int
|
||||
|
||||
internal final class MyClass {
|
||||
public constructor MyClass(/*0*/ p: kotlin.Any)
|
||||
internal final var p: kotlin.Any
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
internal final fun foo(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fun bar(s: Any): Int {
|
||||
return s.hashCode()
|
||||
}
|
||||
|
||||
class MyClass(var p: Any) {
|
||||
fun foo(): Int {
|
||||
p = "xyz"
|
||||
if (p is String) {
|
||||
return bar(p)
|
||||
}
|
||||
return -1
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package
|
||||
|
||||
internal fun bar(/*0*/ s: kotlin.Any): kotlin.Int
|
||||
|
||||
internal final class MyClass {
|
||||
public constructor MyClass(/*0*/ p: kotlin.Any)
|
||||
internal final var p: kotlin.Any
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
internal final fun foo(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fun get(): Any {
|
||||
return ""
|
||||
}
|
||||
|
||||
fun foo(): Int {
|
||||
var c: Any = get()
|
||||
(c as String).length()
|
||||
return <!DEBUG_INFO_SMARTCAST!>c<!>.length() // Previous line should make as unnecessary here.
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
internal fun foo(): kotlin.Int
|
||||
internal fun get(): kotlin.Any
|
||||
@@ -0,0 +1,9 @@
|
||||
public fun foo() {
|
||||
var i: Any = 1
|
||||
if (i is Int) {
|
||||
while (i != 10) {
|
||||
<!UNUSED_CHANGED_VALUE!>i<!UNRESOLVED_REFERENCE!>++<!><!> // Here smart cast should not be performed due to a successor
|
||||
i = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
public fun foo(): kotlin.Unit
|
||||
@@ -0,0 +1,8 @@
|
||||
public fun foo() {
|
||||
var i: Any = 1
|
||||
if (i is Int) {
|
||||
while (i != 10) {
|
||||
<!DEBUG_INFO_SMARTCAST!>i<!>++
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
public fun foo(): kotlin.Unit
|
||||
@@ -0,0 +1,13 @@
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(pp: Any): Int {
|
||||
var p = pp
|
||||
while(true) {
|
||||
(p as String).length()
|
||||
if (x()) break
|
||||
p = 42
|
||||
}
|
||||
// Smart cast is NOT possible here
|
||||
// (we could provide it but p = 42 makes it difficult to understand)
|
||||
return p.<!UNRESOLVED_REFERENCE!>length<!>()
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
public fun foo(/*0*/ pp: kotlin.Any): kotlin.Int
|
||||
internal fun x(): kotlin.Boolean
|
||||
@@ -0,0 +1,17 @@
|
||||
fun String.next(): String {
|
||||
return "abc"
|
||||
}
|
||||
|
||||
fun list(start: String) {
|
||||
var e: Any? = start
|
||||
if (e==null) return
|
||||
while (e is String) {
|
||||
// Smart cast due to the loop condition
|
||||
if (<!DEBUG_INFO_SMARTCAST!>e<!>.length() == 0)
|
||||
break
|
||||
// We still have smart cast here despite of a break
|
||||
e = <!DEBUG_INFO_SMARTCAST!>e<!>.next()
|
||||
}
|
||||
// e can never be null but we do not know it
|
||||
e<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
internal fun list(/*0*/ start: kotlin.String): kotlin.Unit
|
||||
internal fun kotlin.String.next(): kotlin.String
|
||||
Reference in New Issue
Block a user