Files
Brian Norman b2041e0927 [FIR] Disable data flow from in-place lambdas
There are many complications with the current design of passing data
from within in-place lambdas to surrounding code. Solving these
complications will involve more time to investigation than is available
within the K2 release. So we are disabling passing type statement
information from lambdas for the time being until more time can be
devoted to a more complete solution.

^KT-60958 Fixed
^KT-63530 Fixed
2023-12-14 16:40:27 +00:00

91 lines
2.6 KiB
Kotlin
Vendored

// !DUMP_CFG
import kotlin.contracts.*
fun <T> n(): T? = null
@OptIn(ExperimentalContracts::class)
fun <T> run2(x: () -> T, y: () -> T) {
contract {
callsInPlace(x, InvocationKind.EXACTLY_ONCE)
callsInPlace(y, InvocationKind.EXACTLY_ONCE)
}
x()
y()
}
fun test1(x: String?) {
var p = x
if (p != null) {
run2(
{ p = null; n() },
{ <!SMARTCAST_IMPOSSIBLE!>p<!>.length; 123 } // Bad: may or may not not be called first
)
p<!UNSAFE_CALL!>.<!>length // Bad: p = null
}
}
fun test1_tail(x: String?) {
var p = x
if (p != null) {
run2({ p = null; n() }) {
<!SMARTCAST_IMPOSSIBLE!>p<!>.length // Bad: may or may not not be called first
123
}
p<!UNSAFE_CALL!>.<!>length // Bad: p = null
}
}
fun test2(x: Any?) {
var p: Any? = x
p.<!UNRESOLVED_REFERENCE!>length<!> // Bad
run2({ p = null; n() }, { p as String; 123 })
p.<!UNRESOLVED_REFERENCE!>length<!> // Bad: p is Nothing? | (String & Nothing?) = Nothing?
p?.<!UNRESOLVED_REFERENCE!>length<!> // Technically OK because p is null, but what is "length"?
}
fun test3(x: Any?) {
var p: Any? = x
p.<!UNRESOLVED_REFERENCE!>length<!> // Bad
run2({ p = null; n() }, { p = ""; 123 })
p.<!UNRESOLVED_REFERENCE!>length<!> // Bad: p can be null
p?.<!UNRESOLVED_REFERENCE!>length<!> // Bad: KT-37838 -> OK: p is String | Nothing? = String?
}
interface I1 { val x: Int }
interface I2 { val y: Int }
fun test4(x: Any?) {
x.<!UNRESOLVED_REFERENCE!>x<!> // Bad
x.<!UNRESOLVED_REFERENCE!>y<!> // Bad
run2(
{ x as I1; x.<!UNRESOLVED_REFERENCE!>y<!>; n() }, // Bad: may or may not be called first
{ x as I2; x.<!UNRESOLVED_REFERENCE!>x<!>; 123 } // Bad: may or may not be called first
)
x.<!UNRESOLVED_REFERENCE!>x<!> // Bad: KT-37838 -> OK: x is I1 & I2
x.<!UNRESOLVED_REFERENCE!>y<!> // Bad: KT-37838 -> OK: x is I1 & I2
}
fun test5(x: Any?, q: String?) {
var p: Any? = x
p.<!UNRESOLVED_REFERENCE!>length<!> // Bad
run2({ p as Int; 123 }, { p = q; n() })
p.<!UNRESOLVED_REFERENCE!>length<!> // Bad: p is String? | (String? & Int) = String?
p?.<!UNRESOLVED_REFERENCE!>length<!> // Bad: KT-37838 -> OK: p is String?
}
fun test6() {
val x: String
// not necessarily initialized in second lambda (may call in any order)
run2({ x = ""; x.length }, { <!UNINITIALIZED_VARIABLE!>x<!>.length })
x.length // initialized here
}
fun test7() {
val x: Any? = ""
val y: Any?
run2({ y = x }, { })
if (y is String) {
x.length // ok - aliased
}
}