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:
@@ -10,10 +10,11 @@ fun foo1(e: PsiElement) {
|
||||
var first = true
|
||||
while (current != null) {
|
||||
if (current is JetExpression && first) {
|
||||
println(current!!.getText()) // error: smart cast not possible. But it's not needed in fact!
|
||||
// Smartcast is possible here
|
||||
println(<!DEBUG_INFO_SMARTCAST!>current<!>.getText())
|
||||
}
|
||||
|
||||
current = current?.getParent()
|
||||
current = <!DEBUG_INFO_SMARTCAST!>current<!>.getParent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
fun foo() {
|
||||
var v: String? = null
|
||||
v<!UNSAFE_CALL!>.<!>length()
|
||||
v = "abc"
|
||||
<!DEBUG_INFO_SMARTCAST!>v<!>.length()
|
||||
v = null
|
||||
v<!UNSAFE_CALL!>.<!>length()
|
||||
v = "abc"
|
||||
<!DEBUG_INFO_SMARTCAST!>v<!>.length()
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
internal fun foo(): kotlin.Unit
|
||||
@@ -0,0 +1,21 @@
|
||||
data class SomeObject(val n: SomeObject?) {
|
||||
fun doSomething(): Boolean = true
|
||||
fun next(): SomeObject? = n
|
||||
}
|
||||
|
||||
|
||||
fun list(start: SomeObject) {
|
||||
var e: SomeObject?
|
||||
e = start
|
||||
do {
|
||||
// In theory smart cast is possible here
|
||||
// But in practice we have a loop with changing e
|
||||
// ?: should we "or" entrance type info with condition type info?
|
||||
if (!e<!UNSAFE_CALL!>.<!>doSomething())
|
||||
break
|
||||
// Smart cast here is still not possible
|
||||
e = e<!UNSAFE_CALL!>.<!>next()
|
||||
} while (e != null)
|
||||
// e can be null because of next()
|
||||
e<!UNSAFE_CALL!>.<!>doSomething()
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package
|
||||
|
||||
internal fun list(/*0*/ start: SomeObject): kotlin.Unit
|
||||
|
||||
kotlin.data() internal final class SomeObject {
|
||||
public constructor SomeObject(/*0*/ n: SomeObject?)
|
||||
internal final val n: SomeObject?
|
||||
internal final /*synthesized*/ fun component1(): SomeObject?
|
||||
public final /*synthesized*/ fun copy(/*0*/ n: SomeObject? = ...): SomeObject
|
||||
internal final fun doSomething(): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
internal final fun next(): SomeObject?
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(pp: String?): Int {
|
||||
var p = pp
|
||||
do {
|
||||
p!!.length()
|
||||
if (p == "abc") break
|
||||
p = null
|
||||
} while (!x())
|
||||
// Smart cast is NOT possible here
|
||||
return p<!UNSAFE_CALL!>.<!>length()
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
public fun foo(/*0*/ pp: kotlin.String?): kotlin.Int
|
||||
internal fun x(): kotlin.Boolean
|
||||
@@ -0,0 +1,16 @@
|
||||
data class SomeObject(val n: SomeObject?) {
|
||||
fun doSomething() {}
|
||||
fun next(): SomeObject? = n
|
||||
}
|
||||
|
||||
|
||||
fun list(start: SomeObject): SomeObject {
|
||||
var e: SomeObject? = start
|
||||
for (i in 0..42) {
|
||||
// Unsafe calls because of nullable e at the beginning
|
||||
e<!UNSAFE_CALL!>.<!>doSomething()
|
||||
e = e<!UNSAFE_CALL!>.<!>next()
|
||||
}
|
||||
// Smart cast is not possible here due to next()
|
||||
return <!TYPE_MISMATCH!>e<!>
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package
|
||||
|
||||
internal fun list(/*0*/ start: SomeObject): SomeObject
|
||||
|
||||
kotlin.data() internal final class SomeObject {
|
||||
public constructor SomeObject(/*0*/ n: SomeObject?)
|
||||
internal final val n: SomeObject?
|
||||
internal final /*synthesized*/ fun component1(): SomeObject?
|
||||
public final /*synthesized*/ fun copy(/*0*/ n: SomeObject? = ...): SomeObject
|
||||
internal final fun doSomething(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
internal final fun next(): SomeObject?
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
data class SomeObject(val n: SomeObject?) {
|
||||
fun doSomething() {}
|
||||
fun next(): SomeObject? = n
|
||||
}
|
||||
|
||||
|
||||
fun list(start: SomeObject): SomeObject {
|
||||
var e: SomeObject? = start
|
||||
for (i in 0..42) {
|
||||
if (e == null)
|
||||
break
|
||||
// Smart casts are possible because of the break before
|
||||
<!DEBUG_INFO_SMARTCAST!>e<!>.doSomething()
|
||||
e = <!DEBUG_INFO_SMARTCAST!>e<!>.next()
|
||||
}
|
||||
return <!TYPE_MISMATCH!>e<!>
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package
|
||||
|
||||
internal fun list(/*0*/ start: SomeObject): SomeObject
|
||||
|
||||
kotlin.data() internal final class SomeObject {
|
||||
public constructor SomeObject(/*0*/ n: SomeObject?)
|
||||
internal final val n: SomeObject?
|
||||
internal final /*synthesized*/ fun component1(): SomeObject?
|
||||
public final /*synthesized*/ fun copy(/*0*/ n: SomeObject? = ...): SomeObject
|
||||
internal final fun doSomething(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
internal final fun next(): SomeObject?
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
data class SomeObject(val n: SomeObject?) {
|
||||
fun doSomething() {}
|
||||
fun next(): SomeObject? = n
|
||||
}
|
||||
|
||||
|
||||
fun list(start: SomeObject): SomeObject {
|
||||
var e: SomeObject? = start
|
||||
for (i in 0..42) {
|
||||
if (e == null)
|
||||
continue
|
||||
// Smart casts are possible because of the continue before
|
||||
<!DEBUG_INFO_SMARTCAST!>e<!>.doSomething()
|
||||
e = <!DEBUG_INFO_SMARTCAST!>e<!>.next()
|
||||
}
|
||||
return <!TYPE_MISMATCH!>e<!>
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package
|
||||
|
||||
internal fun list(/*0*/ start: SomeObject): SomeObject
|
||||
|
||||
kotlin.data() internal final class SomeObject {
|
||||
public constructor SomeObject(/*0*/ n: SomeObject?)
|
||||
internal final val n: SomeObject?
|
||||
internal final /*synthesized*/ fun component1(): SomeObject?
|
||||
public final /*synthesized*/ fun copy(/*0*/ n: SomeObject? = ...): SomeObject
|
||||
internal final fun doSomething(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
internal final fun next(): SomeObject?
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
public fun fooNotNull(s: String) {
|
||||
System.out.println("Length of $s is ${s.length()}")
|
||||
}
|
||||
|
||||
public fun foo() {
|
||||
var s: String? = "not null"
|
||||
if (s != null)
|
||||
fooNotNull(<!DEBUG_INFO_SMARTCAST!>s<!>)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
public fun foo(): kotlin.Unit
|
||||
public fun fooNotNull(/*0*/ s: kotlin.String): kotlin.Unit
|
||||
@@ -0,0 +1,13 @@
|
||||
// See KT-5737
|
||||
fun get(): String? {
|
||||
return "abc"
|
||||
}
|
||||
|
||||
fun foo(): Int {
|
||||
var ss:String? = get()
|
||||
|
||||
return if (ss != null && <!DEBUG_INFO_SMARTCAST!>ss<!>.length() > 0)
|
||||
1
|
||||
else
|
||||
0
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
internal fun foo(): kotlin.Int
|
||||
internal fun get(): kotlin.String?
|
||||
@@ -0,0 +1,12 @@
|
||||
public fun fooNotNull(s: String) {
|
||||
System.out.println("Length of $s is ${s.length()}")
|
||||
}
|
||||
|
||||
public fun foo() {
|
||||
var s: String? = "not null"
|
||||
if (s == null) {
|
||||
// Coming soon
|
||||
} else {
|
||||
fooNotNull(<!DEBUG_INFO_SMARTCAST!>s<!>)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
public fun foo(): kotlin.Unit
|
||||
public fun fooNotNull(/*0*/ s: kotlin.String): kotlin.Unit
|
||||
@@ -0,0 +1,11 @@
|
||||
public fun fooNotNull(s: String) {
|
||||
System.out.println("Length of $s is ${s.length()}")
|
||||
}
|
||||
|
||||
public fun foo() {
|
||||
var s: String? = "not null"
|
||||
if (s == null) {
|
||||
return
|
||||
}
|
||||
fooNotNull(<!DEBUG_INFO_SMARTCAST!>s<!>)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
public fun foo(): kotlin.Unit
|
||||
public fun fooNotNull(/*0*/ s: kotlin.String): kotlin.Unit
|
||||
@@ -0,0 +1,21 @@
|
||||
// See KT-969
|
||||
fun f() {
|
||||
var s: String?
|
||||
s = "a"
|
||||
var s1 = "" // String – ?
|
||||
if (<!SENSELESS_COMPARISON!>s != null<!>) { // Redundant
|
||||
s1.length()
|
||||
// We can do smartcast here and below
|
||||
s1 = <!DEBUG_INFO_SMARTCAST!>s<!>.toString() // return String?
|
||||
s1.length()
|
||||
s1 = <!DEBUG_INFO_SMARTCAST!>s<!>
|
||||
s1.length()
|
||||
// It's just an assignment without smartcast
|
||||
val s2 = s
|
||||
// But smartcast can be done here
|
||||
<!DEBUG_INFO_SMARTCAST!>s2<!>.length()
|
||||
// And also here
|
||||
val s3 = <!DEBUG_INFO_SMARTCAST!>s<!>.toString()
|
||||
s3.length()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
internal fun f(): kotlin.Unit
|
||||
@@ -0,0 +1,20 @@
|
||||
data class SomeObject(val n: SomeObject?) {
|
||||
fun doSomething(): Boolean = true
|
||||
fun next(): SomeObject? = n
|
||||
}
|
||||
|
||||
|
||||
fun list(start: SomeObject) {
|
||||
var e: SomeObject?
|
||||
e = start
|
||||
// This comparison is senseless
|
||||
while (e != null) {
|
||||
// Smart cast because of the loop condition
|
||||
if (!<!DEBUG_INFO_SMARTCAST!>e<!>.doSomething())
|
||||
break
|
||||
// We still have smart cast here despite of a break
|
||||
e = <!DEBUG_INFO_SMARTCAST!>e<!>.next()
|
||||
}
|
||||
// e can be null because of next()
|
||||
e<!UNSAFE_CALL!>.<!>doSomething()
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package
|
||||
|
||||
internal fun list(/*0*/ start: SomeObject): kotlin.Unit
|
||||
|
||||
kotlin.data() internal final class SomeObject {
|
||||
public constructor SomeObject(/*0*/ n: SomeObject?)
|
||||
internal final val n: SomeObject?
|
||||
internal final /*synthesized*/ fun component1(): SomeObject?
|
||||
public final /*synthesized*/ fun copy(/*0*/ n: SomeObject? = ...): SomeObject
|
||||
internal final fun doSomething(): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
internal final fun next(): SomeObject?
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// See KT-774
|
||||
fun box() : Int {
|
||||
var a : Int? = 1
|
||||
var d = 1
|
||||
|
||||
if (a == null) {
|
||||
return 2
|
||||
} else {
|
||||
return <!DEBUG_INFO_SMARTCAST!>a<!> + d
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
internal fun box(): kotlin.Int
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo() {
|
||||
var v: String? = "xyz"
|
||||
// It is possible in principle to provide smart cast here
|
||||
v<!UNSAFE_CALL!>.<!>length()
|
||||
v = null
|
||||
v<!UNSAFE_CALL!>.<!>length()
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
internal fun foo(): kotlin.Unit
|
||||
@@ -0,0 +1,14 @@
|
||||
data class SomeObject(val n: SomeObject?) {
|
||||
fun doSomething() {}
|
||||
fun next(): SomeObject? = n
|
||||
}
|
||||
|
||||
|
||||
fun list(start: SomeObject) {
|
||||
var e: SomeObject? = start
|
||||
while (e != null) {
|
||||
// While condition makes both smart casts possible
|
||||
<!DEBUG_INFO_SMARTCAST!>e<!>.doSomething()
|
||||
e = <!DEBUG_INFO_SMARTCAST!>e<!>.next()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package
|
||||
|
||||
internal fun list(/*0*/ start: SomeObject): kotlin.Unit
|
||||
|
||||
kotlin.data() internal final class SomeObject {
|
||||
public constructor SomeObject(/*0*/ n: SomeObject?)
|
||||
internal final val n: SomeObject?
|
||||
internal final /*synthesized*/ fun component1(): SomeObject?
|
||||
public final /*synthesized*/ fun copy(/*0*/ n: SomeObject? = ...): SomeObject
|
||||
internal final fun doSomething(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
internal final fun next(): SomeObject?
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(pp: String?, rr: String?): Int {
|
||||
var p = pp
|
||||
var r = rr
|
||||
do {
|
||||
do {
|
||||
p!!.length()
|
||||
} while (r == null)
|
||||
} while (!x())
|
||||
// Auto cast possible
|
||||
<!DEBUG_INFO_SMARTCAST!>r<!>.length()
|
||||
// Auto cast possible
|
||||
return <!DEBUG_INFO_SMARTCAST!>p<!>.length()
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
public fun foo(/*0*/ pp: kotlin.String?, /*1*/ rr: kotlin.String?): kotlin.Int
|
||||
internal fun x(): kotlin.Boolean
|
||||
@@ -0,0 +1,19 @@
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(qq: String?): Int {
|
||||
var q = qq
|
||||
while(true) {
|
||||
q!!.length()
|
||||
var r = q
|
||||
do {
|
||||
var p = r
|
||||
do {
|
||||
// p = r, r = q and q is not null
|
||||
<!DEBUG_INFO_SMARTCAST!>p<!>.length()
|
||||
} while (!x())
|
||||
} while (<!SENSELESS_COMPARISON!>r == null<!>) // r = q and q is not null
|
||||
if (!x()) break
|
||||
}
|
||||
// Smart cast is possible
|
||||
return <!DEBUG_INFO_SMARTCAST!>q<!>.length()
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
public fun foo(/*0*/ qq: kotlin.String?): kotlin.Int
|
||||
internal fun x(): kotlin.Boolean
|
||||
@@ -0,0 +1,27 @@
|
||||
class Bar {
|
||||
fun next(): Bar? {
|
||||
if (2 == 4)
|
||||
return this
|
||||
else
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun foo(): Bar {
|
||||
var x: Bar? = Bar()
|
||||
var y: Bar? = Bar()
|
||||
while (x != null) {
|
||||
// Here call is unsafe because of initialization and also inner loop
|
||||
y<!UNSAFE_CALL!>.<!>next()
|
||||
while (y != null) {
|
||||
if (x == y)
|
||||
// x is not null because of outer while
|
||||
return <!DEBUG_INFO_SMARTCAST!>x<!>
|
||||
// y is not null because of inner while
|
||||
y = <!DEBUG_INFO_SMARTCAST!>y<!>.next()
|
||||
}
|
||||
// x is not null because of outer while
|
||||
x = <!DEBUG_INFO_SMARTCAST!>x<!>.next()
|
||||
}
|
||||
return Bar()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package
|
||||
|
||||
internal fun foo(): Bar
|
||||
|
||||
internal final class Bar {
|
||||
public constructor Bar()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
internal final fun next(): Bar?
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fun String?.foo(): String {
|
||||
return this ?: ""
|
||||
}
|
||||
|
||||
class MyClass {
|
||||
private var s: String? = null
|
||||
|
||||
fun bar(): String {
|
||||
s = "42"
|
||||
return s.foo()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package
|
||||
|
||||
internal fun kotlin.String?.foo(): kotlin.String
|
||||
|
||||
internal final class MyClass {
|
||||
public constructor MyClass()
|
||||
private final var s: kotlin.String?
|
||||
internal final fun bar(): 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,12 @@
|
||||
fun String?.foo(): String {
|
||||
return this ?: ""
|
||||
}
|
||||
|
||||
class MyClass {
|
||||
fun bar(): String {
|
||||
var s: String? = null
|
||||
if (4 < 2)
|
||||
s = "42"
|
||||
return s.foo()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package
|
||||
|
||||
internal fun kotlin.String?.foo(): kotlin.String
|
||||
|
||||
internal final class MyClass {
|
||||
public constructor MyClass()
|
||||
internal final fun bar(): 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,19 @@
|
||||
fun create(): Map<String, String> = null!!
|
||||
|
||||
fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = null!!
|
||||
|
||||
fun <K, V> Map.Entry<K, V>.component1() = getKey()
|
||||
|
||||
fun <K, V> Map.Entry<K, V>.component2() = getValue()
|
||||
|
||||
class MyClass {
|
||||
private var m: Map<String, String>? = null
|
||||
fun foo(): Int {
|
||||
var res = 0
|
||||
m = create()
|
||||
// See KT-7428
|
||||
for ((k, v) in <!SMARTCAST_IMPOSSIBLE!>m<!>)
|
||||
res += (k.length() + v.length())
|
||||
return res
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package
|
||||
|
||||
internal fun create(): kotlin.Map<kotlin.String, kotlin.String>
|
||||
internal fun </*0*/ K, /*1*/ V> kotlin.Map.Entry<K, V>.component1(): K
|
||||
internal fun </*0*/ K, /*1*/ V> kotlin.Map.Entry<K, V>.component2(): V
|
||||
internal fun </*0*/ K, /*1*/ V> kotlin.Map<K, V>.iterator(): kotlin.Iterator<kotlin.Map.Entry<K, V>>
|
||||
|
||||
internal final class MyClass {
|
||||
public constructor MyClass()
|
||||
private final var m: kotlin.Map<kotlin.String, kotlin.String>?
|
||||
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,17 @@
|
||||
public fun foo() {
|
||||
var s: String? = ""
|
||||
fun closure(): Int {
|
||||
if (s == "") {
|
||||
s = null
|
||||
return -1
|
||||
} else if (s == null) {
|
||||
return -2
|
||||
} else {
|
||||
return s<!UNSAFE_CALL!>.<!>length() // Here smartcast is possible, at least in principle
|
||||
}
|
||||
}
|
||||
if (s != null) {
|
||||
System.out.println(closure())
|
||||
System.out.println(s<!UNSAFE_CALL!>.<!>length()) // Here smartcast is not possible due to a closure predecessor
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
public fun foo(): kotlin.Unit
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// See also KT-7186
|
||||
|
||||
fun IntArray.forEachIndexed( op: (i: Int, value: Int) -> Unit) {
|
||||
for (i in 0..this.size()-1)
|
||||
op(i, this[i])
|
||||
}
|
||||
|
||||
fun max(a: IntArray): Int? {
|
||||
var maxI: Int? = null
|
||||
a.forEachIndexed { i, value ->
|
||||
if (maxI == null || value >= a[<!TYPE_MISMATCH!>maxI<!>])
|
||||
maxI = i
|
||||
}
|
||||
return maxI
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
internal fun max(/*0*/ a: kotlin.IntArray): kotlin.Int?
|
||||
internal fun kotlin.IntArray.forEachIndexed(/*0*/ op: (kotlin.Int, kotlin.Int) -> kotlin.Unit): kotlin.Unit
|
||||
@@ -0,0 +1,15 @@
|
||||
public fun foo() {
|
||||
var s: String? = ""
|
||||
fun closure(): Int {
|
||||
if (s == null) {
|
||||
return -1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
if (s != null) {
|
||||
System.out.println(closure())
|
||||
// Smart cast is possible but closure makes it harder to understand
|
||||
System.out.println(s<!UNSAFE_CALL!>.<!>length())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
public fun foo(): kotlin.Unit
|
||||
@@ -0,0 +1,9 @@
|
||||
public fun foo() {
|
||||
var i: Int? = 1
|
||||
if (i != null) {
|
||||
while (i != 10) {
|
||||
<!UNUSED_CHANGED_VALUE!>i<!UNSAFE_CALL!>++<!><!> // Here smart cast should not be performed due to a successor
|
||||
i = null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
public fun foo(): kotlin.Unit
|
||||
@@ -0,0 +1,9 @@
|
||||
fun get(): String? {
|
||||
return ""
|
||||
}
|
||||
|
||||
fun foo(): Int {
|
||||
var c: String? = get()
|
||||
c!!.length()
|
||||
return <!DEBUG_INFO_SMARTCAST!>c<!>.length() // Previous line should make !! unnecessary here.
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
internal fun foo(): kotlin.Int
|
||||
internal fun get(): kotlin.String?
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(): Int {
|
||||
var i: Int? = <!VARIABLE_WITH_REDUNDANT_INITIALIZER!>42<!>
|
||||
i = null
|
||||
return i <!UNSAFE_INFIX_CALL!>+<!> 1
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
internal fun foo(): kotlin.Int
|
||||
@@ -0,0 +1,8 @@
|
||||
public fun foo() {
|
||||
var i: Int? = 1
|
||||
if (i != null) {
|
||||
while (i != 10) {
|
||||
<!DEBUG_INFO_SMARTCAST!>i<!>++
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
public fun foo(): kotlin.Unit
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(): Int {
|
||||
var s: String? = <!VARIABLE_WITH_REDUNDANT_INITIALIZER!>"abc"<!>
|
||||
s = null
|
||||
return s<!UNSAFE_CALL!>.<!>length()
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package
|
||||
|
||||
internal fun foo(): kotlin.Int
|
||||
@@ -0,0 +1,13 @@
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(pp: String?): Int {
|
||||
var p = pp
|
||||
while(true) {
|
||||
p!!.length()
|
||||
if (x()) break
|
||||
p = null
|
||||
}
|
||||
// Smart cast is NOT possible here
|
||||
// (we could provide it but p = null makes it much harder)
|
||||
return p<!UNSAFE_CALL!>.<!>length()
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
public fun foo(/*0*/ pp: kotlin.String?): kotlin.Int
|
||||
internal fun x(): kotlin.Boolean
|
||||
@@ -0,0 +1,17 @@
|
||||
data class SomeObject(val n: SomeObject?) {
|
||||
fun doSomething(): Boolean = true
|
||||
fun next(): SomeObject? = n
|
||||
}
|
||||
|
||||
fun list(start: SomeObject) {
|
||||
var e: SomeObject? = start
|
||||
while (e != null) {
|
||||
// Smart cast due to the loop condition
|
||||
if (!<!DEBUG_INFO_SMARTCAST!>e<!>.doSomething())
|
||||
break
|
||||
// We still have smart cast here despite of a break
|
||||
e = <!DEBUG_INFO_SMARTCAST!>e<!>.next()
|
||||
}
|
||||
// e can be null because of next()
|
||||
e<!UNSAFE_CALL!>.<!>doSomething()
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user