FIR checker: report SMARTCAST_IMPOSSIBLE for local variables

This commit is contained in:
Tianyu Geng
2021-05-13 17:23:18 -07:00
committed by TeamCityServer
parent 092750e215
commit 0ecc752813
38 changed files with 792 additions and 99 deletions
@@ -1,6 +1,6 @@
class My {
val y: Int
val y: Int
get() {
var x: Int?
x = 3
@@ -0,0 +1,56 @@
import kotlin.contracts.*
@Suppress("EXPERIMENTAL_API_USAGE_ERROR")
inline fun atLeastOnce(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
}
block()
}
@Suppress("EXPERIMENTAL_API_USAGE_ERROR")
inline fun atMostOnce(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
}
block()
}
@Suppress("EXPERIMENTAL_API_USAGE_ERROR")
inline fun exactlyOnce(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
}
fun test() {
var s: String? = null
s = ""
atLeastOnce {
<!SMARTCAST_IMPOSSIBLE!>s<!>.length // unstable since lambda can be called twice
s = null
var s2: String? = null
s2 = ""
s2.length // local variable declared inside lambda is stable
s2 = null
}
s = ""
exactlyOnce {
s.length // stable since lambda can be called only once
s = null
var s2: String? = null
s2 = ""
s2.length // local variable declared inside lambda is stable
s2 = null
}
s = ""
atMostOnce {
s.length // stable since lambda can be called at most once
s = null
var s2: String? = null
s2 = ""
s2.length // local variable declared inside lambda is stable
s2 = null
}
}
@@ -0,0 +1,56 @@
import kotlin.contracts.*
@Suppress("EXPERIMENTAL_API_USAGE_ERROR")
inline fun atLeastOnce(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
}
block()
}
@Suppress("EXPERIMENTAL_API_USAGE_ERROR")
inline fun atMostOnce(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
}
block()
}
@Suppress("EXPERIMENTAL_API_USAGE_ERROR")
inline fun exactlyOnce(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
}
fun test() {
var s: String? = <!VARIABLE_WITH_REDUNDANT_INITIALIZER!>null<!>
s = ""
atLeastOnce {
<!SMARTCAST_IMPOSSIBLE!>s<!>.length // unstable since lambda can be called twice
s = null
var s2: String? = <!VARIABLE_WITH_REDUNDANT_INITIALIZER!>null<!>
s2 = ""
<!DEBUG_INFO_SMARTCAST!>s2<!>.length // local variable declared inside lambda is stable
s2 = null
}
s = ""
exactlyOnce {
<!SMARTCAST_IMPOSSIBLE!>s<!>.length // stable since lambda can be called only once
s = null
var s2: String? = <!VARIABLE_WITH_REDUNDANT_INITIALIZER!>null<!>
s2 = ""
<!SMARTCAST_IMPOSSIBLE!>s2<!>.length // local variable declared inside lambda is stable
s2 = null
}
s = ""
atMostOnce {
<!SMARTCAST_IMPOSSIBLE!>s<!>.length // stable since lambda can be called at most once
s = null
var s2: String? = <!VARIABLE_WITH_REDUNDANT_INITIALIZER!>null<!>
s2 = ""
<!SMARTCAST_IMPOSSIBLE!>s2<!>.length // local variable declared inside lambda is stable
s2 = null
}
}
@@ -0,0 +1,12 @@
package
@kotlin.Suppress(names = {"EXPERIMENTAL_API_USAGE_ERROR"}) public inline fun atLeastOnce(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
CallsInPlace(block, AT_LEAST_ONCE)
@kotlin.Suppress(names = {"EXPERIMENTAL_API_USAGE_ERROR"}) public inline fun atMostOnce(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
CallsInPlace(block, AT_MOST_ONCE)
@kotlin.Suppress(names = {"EXPERIMENTAL_API_USAGE_ERROR"}) public inline fun exactlyOnce(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
CallsInPlace(block, EXACTLY_ONCE)
public fun test(): kotlin.Unit
@@ -0,0 +1,31 @@
import kotlin.contracts.*
@Suppress("EXPERIMENTAL_API_USAGE_ERROR")
fun foo(f1: () -> Unit, f2: () -> Unit) {
contract {
callsInPlace(f1, InvocationKind.EXACTLY_ONCE)
callsInPlace(f2, InvocationKind.EXACTLY_ONCE)
}
f2()
f1()
}
fun test() {
var s: String? = null
s = ""
foo(
{ <!SMARTCAST_IMPOSSIBLE!>s<!>.length }, // unstable since lambda evaluation order is indeterministic
{ s = null },
)
s = ""
foo(
{ s = null },
{ <!SMARTCAST_IMPOSSIBLE!>s<!>.length }, // unstable since lambda evaluation order is indeterministic
)
s = ""
foo(
{ s.length }, // stable
{ s.length }, // stable
)
s = null
}
@@ -0,0 +1,31 @@
import kotlin.contracts.*
@Suppress("EXPERIMENTAL_API_USAGE_ERROR")
fun foo(f1: () -> Unit, f2: () -> Unit) {
contract {
callsInPlace(f1, InvocationKind.EXACTLY_ONCE)
callsInPlace(f2, InvocationKind.EXACTLY_ONCE)
}
f2()
f1()
}
fun test() {
var s: String? = <!VARIABLE_WITH_REDUNDANT_INITIALIZER!>null<!>
s = ""
foo(
{ <!SMARTCAST_IMPOSSIBLE!>s<!>.length }, // unstable since lambda evaluation order is indeterministic
{ s = null },
)
s = ""
foo(
{ s = null },
{ <!SMARTCAST_IMPOSSIBLE!>s<!>.length }, // unstable since lambda evaluation order is indeterministic
)
s = ""
foo(
{ <!SMARTCAST_IMPOSSIBLE!>s<!>.length }, // stable
{ <!SMARTCAST_IMPOSSIBLE!>s<!>.length }, // stable
)
s = null
}
@@ -0,0 +1,8 @@
package
@kotlin.Suppress(names = {"EXPERIMENTAL_API_USAGE_ERROR"}) public fun foo(/*0*/ f1: () -> kotlin.Unit, /*1*/ f2: () -> kotlin.Unit): kotlin.Unit
CallsInPlace(f1, EXACTLY_ONCE)
CallsInPlace(f2, EXACTLY_ONCE)
public fun test(): kotlin.Unit
@@ -5,5 +5,5 @@ fun foo(x: Int, f: () -> Unit, y: Int) {}
fun bar() {
var x: Int?
x = 4
foo(x, { x = null; x<!UNSAFE_CALL!>.<!>hashCode() }, <!ARGUMENT_TYPE_MISMATCH!>x<!>)
foo(x, { x = null; x<!UNSAFE_CALL!>.<!>hashCode() }, <!SMARTCAST_IMPOSSIBLE!>x<!>)
}