mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-05-15 00:21:28 +00:00
The main idea is the following: since we need to generate (fake)continuations before inlining, we move IrClasses of suspend lambdas and continuation classes of named functions into the functions. Thus, it allows the codegen to generate them prior to inlining and the inliner will happily transform them for us. Because of that, lowerings which transform call-site function are likely to change reference to lowered suspend lambdas or functions. Hence, do not rely on references to lowered suspend lambdas or functions, instead, rely on attributes. Do not generate continuation for inline suspend lambdas. Previously, inline suspend lambdas were treated like suspend functions, thus we generated continuations for them. Now we just do not treat them as suspend functions or lambdas during AddContinuationLowering. We should add continuation parameter to them, however. Do not generate secondary constructor for suspend lambdas, otherwise, the inliner is unable to transform them (it requires only one constructor to be present). Generate continuation classes for suspend functions as first statement inside the function. This enables suspend functions in local object inside inline functions. Since we already have attributes inside suspend named functions, we just reuse them to generate continuation class names. This allows us to close the gap between code generated by old back-end and the new one. If a suspend named function captures crossinline lambda, we should generate a template for inliner: a copy of the function without state-machine and a continuation constructor call. The call is needed so the inliner transforms the continuation as well. Refactor CoroutineTransformerMethodVisitor, so it no longer depends on PSI.
78 lines
2.9 KiB
Kotlin
Vendored
78 lines
2.9 KiB
Kotlin
Vendored
// FILE: inlined.kt
|
|
// COMMON_COROUTINES_TEST
|
|
// WITH_RUNTIME
|
|
// WITH_COROUTINES
|
|
// NO_CHECK_LAMBDA_INLINING
|
|
|
|
suspend inline fun inlineMe(c: suspend (String) -> String, d: suspend () -> String): String {
|
|
return c(try { d() } catch (e: Exception) { "Exception 1 ${e.message}" })
|
|
}
|
|
|
|
suspend inline fun noinlineMe(noinline c: suspend (String) -> String, noinline d: suspend () -> String): String {
|
|
return c(try { d() } catch (e: Exception) { "Exception 1 ${e.message}" })
|
|
}
|
|
|
|
suspend inline fun crossinlineMe(crossinline c: suspend (String) -> String, crossinline d: suspend () -> String): String {
|
|
return c(try { d() } catch (e: Exception) { "Exception 1 ${e.message}" })
|
|
}
|
|
|
|
// FILE: inlineSite.kt
|
|
// COMMON_COROUTINES_TEST
|
|
|
|
import COROUTINES_PACKAGE.*
|
|
import helpers.*
|
|
|
|
fun builder(c: suspend () -> Unit) {
|
|
c.startCoroutine(EmptyContinuation)
|
|
}
|
|
|
|
suspend fun yieldString(s: String) = s
|
|
|
|
suspend fun throwException(s: String): String {
|
|
throw RuntimeException(s)
|
|
}
|
|
|
|
suspend fun inlineSite() {
|
|
var res = inlineMe({ it }) { yieldString("OK") }
|
|
if (res != "OK") throw RuntimeException("FAIL 1: $res")
|
|
|
|
res = inlineMe({ it }) { throwException("OK") }
|
|
if (res != "Exception 1 OK") throw RuntimeException("FAIL 2: $res")
|
|
|
|
res = noinlineMe({ it }) { yieldString("OK") }
|
|
if (res != "OK") throw RuntimeException("FAIL 3: $res")
|
|
|
|
res = noinlineMe({ it }) { throwException("OK") }
|
|
if (res != "Exception 1 OK") throw RuntimeException("FAIL 4: $res")
|
|
|
|
res = crossinlineMe({ it }) { yieldString("OK") }
|
|
if (res != "OK") throw RuntimeException("FAIL 5: $res")
|
|
|
|
res = crossinlineMe({ it }) { throwException("OK") }
|
|
if (res != "Exception 1 OK") throw RuntimeException("FAIL 6: $res")
|
|
|
|
res = inlineMe({ try {yieldString(it) } catch (e: Exception) { yieldString("Exception 2 $it") } }) { yieldString("OK") }
|
|
if (res != "OK") throw RuntimeException("FAIL 7: $res")
|
|
|
|
res = inlineMe({ try {throwException(it) } catch (e: Exception) { yieldString("Exception 2 $it") } }) { yieldString("OK") }
|
|
if (res != "Exception 2 OK") throw RuntimeException("FAIL 8: $res")
|
|
|
|
res = noinlineMe({ try {yieldString(it) } catch (e: Exception) { yieldString("Exception 2 $it") } }) { yieldString("OK") }
|
|
if (res != "OK") throw RuntimeException("FAIL 9: $res")
|
|
|
|
res = noinlineMe({ try {throwException(it) } catch (e: Exception) { yieldString("Exception 2 $it") } }) { yieldString("OK") }
|
|
if (res != "Exception 2 OK") throw RuntimeException("FAIL 10: $res")
|
|
|
|
res = crossinlineMe({ try {yieldString(it) } catch (e: Exception) { yieldString("Exception 2 $it") } }) { yieldString("OK") }
|
|
if (res != "OK") throw RuntimeException("FAIL 11: $res")
|
|
|
|
res = crossinlineMe({ try {throwException(it) } catch (e: Exception) { yieldString("Exception 2 $it") } }) { yieldString("OK") }
|
|
if (res != "Exception 2 OK") throw RuntimeException("FAIL 12: $res")
|
|
}
|
|
|
|
fun box(): String {
|
|
builder {
|
|
inlineSite()
|
|
}
|
|
return "OK"
|
|
} |