Implementation and tests for KT-5840 and newly created KT-7204. Now a safe call provides not-null receiver state *inside* argument list. It works also for ?. chains. #KT-5840 Fixed.

On the other hand, argument states do not propagate to successor statements for a safe call. #KT-7204 Fixed. A few additional comments.
This commit is contained in:
Mikhail Glukhikh
2015-03-24 17:03:01 +03:00
parent 79739b7090
commit d92ccad35d
53 changed files with 566 additions and 63 deletions
@@ -0,0 +1,6 @@
fun calc(x: List<String>?, y: Int?): Int {
x?.get(y!! - 1)
// y!! above should not provide smart cast here
val yy: Int = <!TYPE_MISMATCH!>y<!>
return yy + (x?.size() ?: 0)
}
@@ -0,0 +1,3 @@
package
internal fun calc(/*0*/ x: kotlin.List<kotlin.String>?, /*1*/ y: kotlin.Int?): kotlin.Int
@@ -0,0 +1,6 @@
fun calc(x: List<String>?): Int {
// After KT-5840 fix !! assertion should become unnecessary here
x?.get(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.size() - 1)
// x?. or x!! above should not provide smart cast here
return x<!UNSAFE_CALL!>.<!>size()
}
@@ -0,0 +1,3 @@
package
internal fun calc(/*0*/ x: kotlin.List<kotlin.String>?): kotlin.Int
@@ -0,0 +1,6 @@
fun calc(x: List<String>?): Int {
// x should be non-null in arguments list, despite of a chain
x?.subList(0, 1)?.get(<!DEBUG_INFO_SMARTCAST!>x<!>.size())
// But not here!
return x!!.size()
}
@@ -0,0 +1,3 @@
package
internal fun calc(/*0*/ x: kotlin.List<kotlin.String>?): kotlin.Int
@@ -0,0 +1,6 @@
fun calc(x: List<String>?, y: List<Int>?) {
// x and y should be non-null in arguments list, despite of a chains
x?.subList(y?.subList(1, 2)?.get(<!DEBUG_INFO_SMARTCAST!>y<!>.size()) ?: 0,
y?.get(0) ?: 1) // But safe call is NECESSARY here for y
?.get(<!DEBUG_INFO_SMARTCAST!>x<!>.size())
}
@@ -0,0 +1,3 @@
package
internal fun calc(/*0*/ x: kotlin.List<kotlin.String>?, /*1*/ y: kotlin.List<kotlin.Int>?): kotlin.Unit
@@ -0,0 +1,6 @@
fun calc(x: List<String>?): Int {
// x should be non-null in arguments list, despite of a chain
x?.subList(0, 1)<!UNSAFE_CALL!>.<!>get(<!DEBUG_INFO_SMARTCAST!>x<!>.size())
// But not here!
return x!!.size()
}
@@ -0,0 +1,3 @@
package
internal fun calc(/*0*/ x: kotlin.List<kotlin.String>?): kotlin.Int
@@ -0,0 +1,6 @@
fun calc(x: List<String>?): Int {
// x should be non-null in arguments list, including inner call
x?.get(<!DEBUG_INFO_SMARTCAST!>x<!>.get(<!DEBUG_INFO_SMARTCAST!>x<!>.size() - 1).length())
// but not also here!
return x<!UNSAFE_CALL!>.<!>size()
}
@@ -0,0 +1,3 @@
package
internal fun calc(/*0*/ x: kotlin.List<kotlin.String>?): kotlin.Int
@@ -0,0 +1,6 @@
fun String.foo(arg: Int) = this[arg]
fun calc(x: String?) {
// x should be non-null in arguments list
x?.foo(<!DEBUG_INFO_SMARTCAST!>x<!>.length() - 1)
}
@@ -0,0 +1,4 @@
package
internal fun calc(/*0*/ x: kotlin.String?): kotlin.Unit
internal fun kotlin.String.foo(/*0*/ arg: kotlin.Int): kotlin.Char
@@ -0,0 +1,7 @@
fun foo(y: Int) = y
fun calc(x: List<String>?): Int {
foo(x!!.size())
// Here we should have smart cast because of x!!, despite of KT-7204 fixed
return <!DEBUG_INFO_SMARTCAST!>x<!>.size()
}
@@ -0,0 +1,4 @@
package
internal fun calc(/*0*/ x: kotlin.List<kotlin.String>?): kotlin.Int
internal fun foo(/*0*/ y: kotlin.Int): kotlin.Int
@@ -0,0 +1,4 @@
fun calc(x: List<String>?, y: Int?) {
// Smart cast should work here despite of KT-7204 fixed
x?.subList(0, y!!)?.get(<!DEBUG_INFO_SMARTCAST!>y<!>)
}
@@ -0,0 +1,3 @@
package
internal fun calc(/*0*/ x: kotlin.List<kotlin.String>?, /*1*/ y: kotlin.Int?): kotlin.Unit
@@ -0,0 +1,7 @@
fun String.foo(y: Int) = y
fun calc(x: List<String>?): Int {
"abc".foo(x!!.size())
// Here we should have smart cast because of x!!, despite of KT-7204 fixed
return <!DEBUG_INFO_SMARTCAST!>x<!>.size()
}
@@ -0,0 +1,4 @@
package
internal fun calc(/*0*/ x: kotlin.List<kotlin.String>?): kotlin.Int
internal fun kotlin.String.foo(/*0*/ y: kotlin.Int): kotlin.Int
@@ -0,0 +1,5 @@
fun calc(x: List<String>?, y: Int?): Int {
x?.subList(y!! - 1, <!DEBUG_INFO_SMARTCAST!>y<!>)
// y!! above should not provide smart cast here
return <!TYPE_MISMATCH!>y<!>
}
@@ -0,0 +1,3 @@
package
internal fun calc(/*0*/ x: kotlin.List<kotlin.String>?, /*1*/ y: kotlin.Int?): kotlin.Int
@@ -0,0 +1,8 @@
fun foo(x: String): String? = x
fun calc(x: String?, y: String?): Int {
// Smart cast because of y!! in receiver
x?.subSequence(y!!.subSequence(0, 1).length(), <!DEBUG_INFO_SMARTCAST!>y<!>.length())
// No smart cast possible
return y<!UNSAFE_CALL!>.<!>length()
}
@@ -0,0 +1,4 @@
package
internal fun calc(/*0*/ x: kotlin.String?, /*1*/ y: kotlin.String?): kotlin.Int
internal fun foo(/*0*/ x: kotlin.String): kotlin.String?
@@ -0,0 +1,8 @@
fun foo(y: Int): Int {
return y + 1
}
fun calc(x: List<String>?): Int {
// x should be non-null in arguments list
return foo(x?.get(<!DEBUG_INFO_SMARTCAST!>x<!>.size() - 1)!!.length())
}
@@ -0,0 +1,4 @@
package
internal fun calc(/*0*/ x: kotlin.List<kotlin.String>?): kotlin.Int
internal fun foo(/*0*/ y: kotlin.Int): kotlin.Int
@@ -0,0 +1,6 @@
fun calc(x: List<String>?) {
// x should be non-null in arguments list, despite of a chain
x?.subList(0, <!DEBUG_INFO_SMARTCAST!>x<!>.size())?.
subList(0, <!DEBUG_INFO_SMARTCAST!>x<!>.size())?.
get(<!DEBUG_INFO_SMARTCAST!>x<!>.size())
}
@@ -0,0 +1,3 @@
package
internal fun calc(/*0*/ x: kotlin.List<kotlin.String>?): kotlin.Unit
@@ -0,0 +1,6 @@
data class MyClass(val x: String?)
fun foo(y: MyClass): Int {
val z = y.x?.subSequence(0, <!DEBUG_INFO_SMARTCAST!>y.x<!>.length())
return z?.length() ?: -1
}
@@ -0,0 +1,13 @@
package
internal fun foo(/*0*/ y: MyClass): kotlin.Int
kotlin.data() internal final class MyClass {
public constructor MyClass(/*0*/ x: kotlin.String?)
internal final val x: kotlin.String?
internal final /*synthesized*/ fun component1(): kotlin.String?
public final /*synthesized*/ fun copy(/*0*/ x: kotlin.String? = ...): MyClass
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,8 @@
fun foo(x: String): String? = x
fun calc(x: String?): Int {
// Smart cast because of x!! in receiver
foo(x!!)?.subSequence(0, <!DEBUG_INFO_SMARTCAST!>x<!>.length())
// Smart cast because of x!! in receiver
return <!DEBUG_INFO_SMARTCAST!>x<!>.length()
}
@@ -0,0 +1,4 @@
package
internal fun calc(/*0*/ x: kotlin.String?): kotlin.Int
internal fun foo(/*0*/ x: kotlin.String): kotlin.String?
@@ -0,0 +1,8 @@
fun foo(x: String): String? = x
fun calc(x: String?): Int {
// Smart cast because of x!! in receiver
foo(x!!)?.subSequence(0, <!DEBUG_INFO_SMARTCAST!>x<!>.length())?.length()
// Smart cast because of x!! in receiver
return <!DEBUG_INFO_SMARTCAST!>x<!>.length()
}
@@ -0,0 +1,4 @@
package
internal fun calc(/*0*/ x: kotlin.String?): kotlin.Int
internal fun foo(/*0*/ x: kotlin.String): kotlin.String?
@@ -0,0 +1,8 @@
fun foo(x: String): String? = x
fun calc(x: String?, y: Int?): Int {
// Smart cast because of x!! in receiver
foo(x!!)?.subSequence(y!!, <!DEBUG_INFO_SMARTCAST!>x<!>.length())?.length()
// No smart cast possible
return <!TYPE_MISMATCH!>y<!>
}
@@ -0,0 +1,4 @@
package
internal fun calc(/*0*/ x: kotlin.String?, /*1*/ y: kotlin.Int?): kotlin.Int
internal fun foo(/*0*/ x: kotlin.String): kotlin.String?
@@ -0,0 +1,6 @@
fun calc(x: List<String>?): Int {
// x should be non-null in arguments list
x?.get(<!DEBUG_INFO_SMARTCAST!>x<!>.size() - 1)
// but not also here!
return x<!UNSAFE_CALL!>.<!>size()
}
@@ -0,0 +1,3 @@
package
internal fun calc(/*0*/ x: kotlin.List<kotlin.String>?): kotlin.Int
@@ -0,0 +1,6 @@
fun calc(x: List<String>?): Int {
// x should be non-null in arguments list
x?.subList(<!DEBUG_INFO_SMARTCAST!>x<!>.size() - 1, <!DEBUG_INFO_SMARTCAST!>x<!>.size())
// but not also here!
return x<!UNSAFE_CALL!>.<!>size()
}
@@ -0,0 +1,3 @@
package
internal fun calc(/*0*/ x: kotlin.List<kotlin.String>?): kotlin.Int