FIR: Fix leakage of type variables in builder inference for lambdas returning Unit
When BI/incomplete call is present in return argument, it will be added to the main call-tree, leading to requirement violation in `ConstraintSystemCompleter.getOrderedAllTypeVariables` as after `FirBuilderInferenceSession.inferPostponedVariables` it will be completed, and its type variables couldn't be found anymore In K1, we actually do the same, but we are able to find type variables of such calls due to architecture difference: In K2, `getOrderedAllTypeVariables` uses FIR as the main source to lookup In K1, `getOrderedAllTypeVariables` uses resolution atom tree, where candidate/CS of the call is still available after `inferPostponedVariables` In fact, all incomplete calls were analyzed in FULL mode according to the contract of `FirBuilderInferenceSession.addPartiallyResolvedCall`. Thus, it means we normally shouldn't add them to the main call-tree, but accidentally do it as incomplete calls contain non-completed candidate This particular commit addresses the problem partially, only in cases when the expected return type for the lambda is Unit and when the incomplete call is located in the last expression of the lambda In such cases, we can skip the call from the last expression completely, since all potential calls there were analyzed in FULL mode, and couldn't introduce any useful info to the CS of the main call-tree ^KT-54294
This commit is contained in:
committed by
Space Team
parent
ae1622d059
commit
3e6b42083b
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
// WITH_STDLIB
|
||||
// TARGET_BACKEND: JVM
|
||||
class Out<out V>(val v: V)
|
||||
class Box<R> {
|
||||
var boxed: R? = null
|
||||
|
||||
fun set(newValue: R) {
|
||||
boxed = newValue
|
||||
}
|
||||
}
|
||||
|
||||
fun <R> buildBox(fill: Box<R>.() -> Unit): Box<R> {
|
||||
return Box<R>().also {
|
||||
it.fill()
|
||||
}
|
||||
}
|
||||
|
||||
fun foo() =
|
||||
buildBox {
|
||||
set(select(Out("OK"), makeOut())) // problem is here
|
||||
// we keep set in PARTIALLY analyzed state, while we're also trying to incorporate it both into return-type constraining
|
||||
// and builder inference, which introduces non-trivial loop of codependency between those two steps
|
||||
// Due to that, we leak type variables from set call-graph to the system of buildBox, while those variables are already
|
||||
// fixed
|
||||
}
|
||||
|
||||
fun <S> select(a: S, b: S): S = a
|
||||
|
||||
fun <M> makeOut(): Out<M>? = null
|
||||
|
||||
fun box(): String {
|
||||
if (foo().boxed!!.v != "OK") return "FAIL"
|
||||
return "OK"
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// WITH_STDLIB
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// FIR status: KT-58742
|
||||
|
||||
class Out<out V>(val v: V)
|
||||
class Box<R> {
|
||||
var boxed: R? = null
|
||||
|
||||
fun set(newValue: R) {
|
||||
boxed = newValue
|
||||
}
|
||||
}
|
||||
|
||||
fun <R> buildBox(fill: Box<R>.() -> Unit): Box<R> {
|
||||
return Box<R>().also {
|
||||
it.fill()
|
||||
}
|
||||
}
|
||||
|
||||
fun foo() =
|
||||
buildBox {
|
||||
if (true) return@buildBox set(select(Out("OK"), makeOut())) // problem is here
|
||||
Unit
|
||||
}
|
||||
|
||||
fun <S> select(a: S, b: S): S = a
|
||||
|
||||
fun <M> makeOut(): Out<M>? = null
|
||||
|
||||
fun box(): String {
|
||||
if (foo().boxed!!.v != "OK") return "FAIL"
|
||||
return "OK"
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// WITH_STDLIB
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// FIR status: KT-58741
|
||||
|
||||
fun foo() =
|
||||
buildBox {
|
||||
set(select(Out("OK"), makeOut()))
|
||||
}
|
||||
|
||||
|
||||
class Out<out V>(val v: V)
|
||||
class Box<R> {
|
||||
var boxed: R? = null
|
||||
|
||||
fun set(newValue: R): String {
|
||||
boxed = newValue
|
||||
return "set"
|
||||
}
|
||||
}
|
||||
|
||||
fun <R> buildBox(fill: Box<R>.() -> String): Box<R> {
|
||||
return Box<R>().also {
|
||||
require(it.fill() == "set")
|
||||
}
|
||||
}
|
||||
|
||||
fun <S> select(a: S, b: S): S = a
|
||||
|
||||
fun <M> makeOut(): Out<M>? = null
|
||||
|
||||
|
||||
fun box(): String {
|
||||
if (foo().boxed!!.v != "OK") return "FAIL"
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user