FIR checker: report SMARTCAST_IMPOSSIBLE for local variables
This commit is contained in:
committed by
TeamCityServer
parent
092750e215
commit
0ecc752813
@@ -10,5 +10,5 @@ fun use() {
|
||||
// Write to x is AFTER
|
||||
x.hashCode()
|
||||
// No smart cast should be here!
|
||||
foo(bar { x = null }, x<!UNSAFE_CALL!>.<!>hashCode())
|
||||
foo(bar { x = null }, <!SMARTCAST_IMPOSSIBLE!>x<!>.hashCode())
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ fun foo(arg: Int?) {
|
||||
var x = arg
|
||||
if (x == null) return
|
||||
run {
|
||||
// Not safe: x = null later in the owner
|
||||
// Safe: since `run` is in-place
|
||||
x.hashCode()
|
||||
}
|
||||
x = null
|
||||
|
||||
@@ -3,7 +3,7 @@ fun foo(arg: Int?) {
|
||||
var x = arg
|
||||
if (x == null) return
|
||||
run {
|
||||
// Not safe: x = null later in the owner
|
||||
// Safe: since `run` is in-place
|
||||
<!SMARTCAST_IMPOSSIBLE!>x<!>.hashCode()
|
||||
}
|
||||
x = null
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
fun trans(n: Int, f: () -> Boolean) = if (f()) n else null
|
||||
|
||||
fun foo() {
|
||||
var i: Int? = 5
|
||||
if (i != null) {
|
||||
class Changing {
|
||||
fun bar() {
|
||||
i = null
|
||||
}
|
||||
}
|
||||
i.hashCode()
|
||||
Changing().bar()
|
||||
i.hashCode()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun trans(n: Int, f: () -> Boolean) = if (f()) n else null
|
||||
|
||||
fun foo() {
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
fun trans(n: Int, f: () -> Boolean) = if (f()) n else null
|
||||
|
||||
fun foo() {
|
||||
var i: Int? = 5
|
||||
if (i != null) {
|
||||
fun can(): Boolean {
|
||||
i = null
|
||||
return true
|
||||
}
|
||||
i.hashCode()
|
||||
trans(i, ::can)
|
||||
i.hashCode()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun trans(n: Int, f: () -> Boolean) = if (f()) n else null
|
||||
|
||||
fun foo() {
|
||||
|
||||
@@ -10,6 +10,6 @@ fun foo() {
|
||||
i = null
|
||||
}
|
||||
}.bar()
|
||||
i.hashCode()
|
||||
<!SMARTCAST_IMPOSSIBLE!>i<!>.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@ fun foo(arg: Int?) {
|
||||
var x = arg
|
||||
if (x == null) return
|
||||
run {
|
||||
// Unsafe because of owner modification
|
||||
x<!UNSAFE_CALL!>.<!>hashCode()
|
||||
// Stable because `run` is in-place
|
||||
x.hashCode()
|
||||
x = null
|
||||
}
|
||||
if (x != null) x = 42
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ fun foo(arg: Int?) {
|
||||
var x = arg
|
||||
if (x == null) return
|
||||
run {
|
||||
// Unsafe because of owner modification
|
||||
// Stable because `run` is in-place
|
||||
<!SMARTCAST_IMPOSSIBLE!>x<!>.hashCode()
|
||||
x = null
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
class My {
|
||||
|
||||
val y: Int
|
||||
val y: Int
|
||||
get() {
|
||||
var x: Int?
|
||||
x = 3
|
||||
|
||||
+56
@@ -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
|
||||
}
|
||||
}
|
||||
+56
@@ -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
|
||||
}
|
||||
}
|
||||
+12
@@ -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
|
||||
+31
@@ -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
|
||||
}
|
||||
+31
@@ -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
|
||||
}
|
||||
+8
@@ -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
|
||||
|
||||
+1
-1
@@ -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<!>)
|
||||
}
|
||||
|
||||
Vendored
+5
-5
@@ -27,10 +27,10 @@ fun baz(s: String?) {
|
||||
var x = s
|
||||
if (x != null) {
|
||||
run {
|
||||
x.hashCode()
|
||||
<!SMARTCAST_IMPOSSIBLE!>x<!>.hashCode()
|
||||
}
|
||||
run {
|
||||
x<!UNSAFE_CALL!>.<!>hashCode()
|
||||
<!SMARTCAST_IMPOSSIBLE!>x<!>.hashCode()
|
||||
x = null
|
||||
}
|
||||
}
|
||||
@@ -40,11 +40,11 @@ fun gaz(s: String?) {
|
||||
var x = s
|
||||
if (x != null) {
|
||||
run {
|
||||
x<!UNSAFE_CALL!>.<!>hashCode()
|
||||
<!SMARTCAST_IMPOSSIBLE!>x<!>.hashCode()
|
||||
x = null
|
||||
}
|
||||
run {
|
||||
x<!UNSAFE_CALL!>.<!>hashCode()
|
||||
<!SMARTCAST_IMPOSSIBLE!>x<!>.hashCode()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ fun gav(s: String?) {
|
||||
var x = s
|
||||
if (x != null) {
|
||||
run {
|
||||
x.hashCode()
|
||||
<!SMARTCAST_IMPOSSIBLE!>x<!>.hashCode()
|
||||
}
|
||||
x = null
|
||||
}
|
||||
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
public fun foo() {
|
||||
var s: String? = ""
|
||||
fun closure(): Int {
|
||||
if (s == "") {
|
||||
s = null
|
||||
return -1
|
||||
} else if (s == null) {
|
||||
return -2
|
||||
} else {
|
||||
return s.length // Here smartcast is possible, at least in principle
|
||||
}
|
||||
}
|
||||
if (s != null) {
|
||||
System.out.println(closure())
|
||||
System.out.println(s.length) // Here smartcast is not possible due to a closure predecessor
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
public fun foo() {
|
||||
var s: String? = ""
|
||||
fun closure(): Int {
|
||||
@@ -14,4 +15,4 @@ public fun foo() {
|
||||
System.out.println(closure())
|
||||
System.out.println(<!SMARTCAST_IMPOSSIBLE!>s<!>.length) // Here smartcast is not possible due to a closure predecessor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
-15
@@ -1,15 +0,0 @@
|
||||
// See also KT-7186
|
||||
|
||||
fun IntArray.forEachIndexed( op: (i: Int, value: Int) -> Unit) {
|
||||
for (i in 0..this.size)
|
||||
op(i, this[i])
|
||||
}
|
||||
|
||||
fun max(a: IntArray): Int? {
|
||||
var maxI: Int? = null
|
||||
a.forEachIndexed { i, value ->
|
||||
if (maxI == null || value >= a[maxI])
|
||||
maxI = i
|
||||
}
|
||||
return maxI
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// See also KT-7186
|
||||
|
||||
fun IntArray.forEachIndexed( op: (i: Int, value: Int) -> Unit) {
|
||||
|
||||
Reference in New Issue
Block a user