Support crossinline suspend lambda as parameter of inline function

Use fake continuation instead of ALOAD 0 while inlining
Do not generate state machine for inner lambdas and inner objects,
which capture crossinline suspend lambda.

 #KT-19159: Fixed
This commit is contained in:
Ilmir Usmanov
2018-01-18 15:21:19 +03:00
parent 042ca55be7
commit 6854135077
80 changed files with 5214 additions and 144 deletions
@@ -35,7 +35,11 @@ fun builderConsumer(c: suspend () -> Consumer): Consumer {
}
class Container {
var y: String = "FAIL 1"
var y: String = "FAIL 0"
val consumer0 = crossInlineBuilderConsumer { s ->
y = s
}
val consumer1 = crossInlineBuilderConsumer { s ->
builder {
@@ -108,6 +112,9 @@ class Container {
fun box(): String {
val c = Container()
c.consumer0.consume("OK")
if (c.y != "OK") return c.y
c.y = "FAIL 1"
c.consumer1.consume("OK")
if (c.y != "OK") return c.y
c.y = "FAIL 2"
@@ -0,0 +1,58 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
suspend inline fun test1(c: suspend () -> Unit) {
c()
}
suspend inline fun test2(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = { c() }
l()
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun calculate() = "OK"
fun box() : String {
var res = "FAIL 1"
builder {
val a = 1
test2 {
val b = 2
test1 {
val c = a + b // 3
run {
val a = c + 1 // 4
test1 {
val b = c + c // 6
test2 {
val c = b - a // 2
res = "${calculate()} $a$b$c"
}
}
}
}
}
}
if (res != "OK 462") return res
return "OK"
}
@@ -0,0 +1,38 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
inline suspend fun foo(crossinline a: suspend () -> Unit, crossinline b: suspend () -> Unit) {
var x = "OK"
bar { x; a(); b() }
}
inline suspend fun bar(crossinline l: suspend () -> Unit) {
val c : suspend () -> Unit = { l() }
c()
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
fun box(): String {
var y = "fail"
builder {
foo({ y = "O" }) { y += "K" }
}
return y
}
@@ -0,0 +1,100 @@
// FILE: test.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.*
class Controller {
var res = "FAIL 1"
}
val defaultController = Controller()
suspend inline fun test1(controller: Controller = defaultController, crossinline c: suspend Controller.() -> Unit) {
controller.c()
}
suspend inline fun test2(controller: Controller = defaultController, crossinline c: suspend Controller.() -> Unit) {
val l : suspend () -> Unit = {
controller.c()
}
l()
}
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun test3(controller: Controller = defaultController, crossinline c: suspend Controller.() -> Unit) {
val sr = object: SuspendRunnable {
override suspend fun run() {
controller.c()
}
}
sr.run()
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun calculate() = "OK"
fun box() : String {
builder {
test1 {
res = calculate()
}
}
if (defaultController.res != "OK") return defaultController.res
defaultController.res = "FAIL 2"
builder {
test2 {
res = calculate()
}
}
if (defaultController.res != "OK") return defaultController.res
defaultController.res = "FAIL 3"
builder {
test3 {
res = calculate()
}
}
if (defaultController.res != "OK") return defaultController.res
val controller = Controller()
controller.res = "FAIL 4"
builder {
test1(controller) {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 5"
builder {
test2(controller) {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 6"
builder {
test3(controller) {
res = calculate()
}
}
return controller.res
}
@@ -0,0 +1,52 @@
// FILE: test.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.*
class Controller {
var res = "FAIL 1"
}
val defaultController = Controller()
suspend inline fun test(controller: Controller = defaultController, c: suspend Controller.() -> Unit) {
controller.c()
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun calculate() = "OK"
fun box() : String {
builder {
test {
res = calculate()
}
}
if (defaultController.res != "OK") return defaultController.res
val controller = Controller()
controller.res = "FAIL 2"
builder {
test(controller) {
res = calculate()
}
}
return controller.res
}
@@ -0,0 +1,101 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// Are suspend calls possible inside lambda matching to the parameter
inline fun test1(crossinline runner: suspend () -> Unit) {
val l : suspend () -> Unit = { runner() }
builder { l() }
}
interface SuspendRunnable {
suspend fun run()
}
inline fun test2(crossinline c: suspend () -> Unit) {
val sr = object: SuspendRunnable {
override suspend fun run() {
c()
}
}
builder { sr.run() }
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
suspend fun calculate() = "OK"
fun box(): String {
var res = "FAIL 1"
test1 {
res = calculate()
}
if (res != "OK") return res
res = "FAIL 2"
test1 {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 3"
test2 {
res = calculate()
}
if (res != "OK") return res
res = "FAIL 4"
test2 {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 5"
test1 {
test2 {
test1 {
test2 {
test1 {
test2 {
res = calculate()
}
}
}
}
}
}
return res
}
@@ -0,0 +1,128 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// Start coroutine call is possible
// Are suspend calls possible inside lambda matching to the parameter
inline fun test1(noinline c: suspend () -> Unit) {
val l : suspend () -> Unit = { c() }
builder { l() }
}
val EmptyContinuation = object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
}
inline fun test2(noinline c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
interface SuspendRunnable {
suspend fun run()
}
inline fun test3(noinline c: suspend () -> Unit) {
val sr = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
builder { sr.run() }
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
// FILE: box.kt
suspend fun calculate() = "OK"
fun box(): String {
var res = "FAIL 1"
test1 {
res = calculate()
}
if (res != "OK") return res
res = "FAIL 2"
test2 {
res = "OK"
}
if (res != "OK") return res
res = "FAIL 3"
test3 {
res = "OK"
}
if (res != "OK") return res
res = "FAIL 4"
test1 {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 5"
test2 {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 6"
test3 {
test3 {
test3 {
test3 {
test3 {
test3 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 7"
test1 {
test2 {
test3 {
test1 {
test2 {
test3 {
res = calculate()
}
}
}
}
}
}
return res
}
@@ -0,0 +1,111 @@
// FILE: test.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
suspend inline fun test1(c: () -> Unit) {
c()
}
suspend inline fun test2(c: suspend () -> Unit) {
c()
}
suspend inline fun test3(crossinline c: suspend() -> Unit) {
c()
}
suspend inline fun test4(crossinline c: suspend() -> Unit) {
val l : suspend () -> Unit = { c() }
l()
}
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun test5(crossinline c: suspend() -> Unit) {
val sr = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
sr.run()
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
import kotlin.coroutines.experimental.jvm.internal.*
object EmptyContinuation: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
var continuationChanged = true
var savedContinuation: Continuation<Unit>? = null
suspend inline fun saveContinuation() = suspendCoroutineUninterceptedOrReturn<Unit> { c ->
savedContinuation = c
Unit
}
suspend inline fun checkContinuation(continuation: Continuation<Unit>) = suspendCoroutineUninterceptedOrReturn<Unit> { c ->
continuationChanged = (continuation !== c)
Unit
}
fun box() : String {
builder {
saveContinuation()
test1 {
checkContinuation(savedContinuation!!)
}
}
if (continuationChanged) return "FAIL 1"
continuationChanged = true
builder {
saveContinuation()
test2 {
checkContinuation(savedContinuation!!)
}
}
if (continuationChanged) return "FAIL 2"
continuationChanged = true
builder {
saveContinuation()
test3 {
checkContinuation(savedContinuation!!)
}
}
if (continuationChanged) return "FAIL 3"
continuationChanged = false
builder {
saveContinuation()
test4 {
checkContinuation(savedContinuation!!)
}
}
if (!continuationChanged) return "FAIL 4"
continuationChanged = false
builder {
saveContinuation()
test5 {
checkContinuation(savedContinuation!!)
}
}
if (!continuationChanged) return "FAIL 5"
return "OK"
}
@@ -0,0 +1,109 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
suspend inline fun test1(crossinline c: () -> Unit) {
c()
}
suspend inline fun test2(crossinline c: () -> Unit) {
val l = { c() }
l()
}
suspend inline fun test3(crossinline c: () -> Unit) {
val r = object: Runnable {
override fun run() {
c()
}
}
r.run()
}
inline fun transform(crossinline c: suspend () -> Unit) {
builder { c() }
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun box() : String {
var res = "FAIL 1"
builder {
test1 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 2"
builder {
test2 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 3"
builder {
test3 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 4"
builder {
test1 {
transform {
test1 {
res = "OK"
}
}
}
}
if (res != "OK") return res
res = "FAIL 5"
builder {
test2 {
transform {
test2 {
res = "OK"
}
}
}
}
if (res != "OK") return res
res = "FAIL 6"
builder {
test3 {
transform {
test3 {
res = "OK"
}
}
}
}
return res
}
@@ -0,0 +1,134 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// suspend calls possible inside lambda matching to the parameter
suspend inline fun test1(crossinline c: suspend () -> Unit) {
c()
}
suspend inline fun test2(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = { c() }
l()
}
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun test3(crossinline c: suspend () -> Unit) {
val sr = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
sr.run()
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun calculate() = "OK"
fun box() : String {
var res = "FAIL 1"
builder {
test1 {
res = calculate()
}
}
if (res != "OK") return res
res = "FAIL 2"
builder {
test2 {
res = calculate()
}
}
if (res != "OK") return res
res = "FAIL 3"
builder {
test3 {
res = calculate()
}
}
if (res != "OK") return res
res = "FAIL 4"
builder {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 5"
builder {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 6"
builder {
test3 {
test3 {
test3 {
test3 {
test3 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 7"
builder {
test1 {
test2 {
test3 {
test1 {
test2 {
res = calculate()
}
}
}
}
}
}
return res
}
@@ -0,0 +1,109 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
suspend inline fun test1(noinline c: () -> Unit) {
c()
}
suspend inline fun test2(noinline c: () -> Unit) {
val l = { c() }
l()
}
suspend inline fun test3(noinline c: () -> Unit) {
val r = object: Runnable {
override fun run() {
c()
}
}
r.run()
}
inline fun transform(crossinline c: suspend () -> Unit) {
builder { c() }
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun box() : String {
var res = "FAIL 1"
builder {
test1 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 2"
builder {
test2 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 3"
builder {
test3 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 4"
builder {
test1 {
transform {
test1 {
res = "OK"
}
}
}
}
if (res != "OK") return res
res = "FAIL 5"
builder {
test2 {
transform {
test2 {
res = "OK"
}
}
}
}
if (res != "OK") return res
res = "FAIL 6"
builder {
test3 {
transform {
test3 {
res = "OK"
}
}
}
}
return res
}
@@ -0,0 +1,163 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// Are suspend calls possible inside lambda matching to the parameter
// Start coroutine call is possible
// Block is allowed to be called directly inside inline function
suspend inline fun test1(noinline c: suspend () -> Unit) {
val l : suspend () -> Unit = { c() }
builder { l() }
}
object EmptyContinuation: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
}
suspend inline fun test2(noinline c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
suspend inline fun test3(noinline c: suspend () -> Unit) {
c()
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun test4(noinline c: suspend () -> Unit) {
val sr = object: SuspendRunnable {
override suspend fun run() {
c()
}
}
sr.run()
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
suspend fun calculate() = "OK"
fun box(): String {
var res = "FAIL 1"
builder {
test1 {
res = calculate()
}
}
if (res != "OK") return res
res = "FAIL 2"
builder {
test2 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 3"
builder {
test3 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 4"
builder {
test4 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 5"
builder {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 6"
builder {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 7"
builder {
test3 {
test3 {
test3 {
test3 {
test3 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 8"
builder {
test4 {
test4 {
test4 {
test4 {
test4 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 9"
builder {
test1 {
test2 {
test3 {
test4 {
test1 {
res = calculate()
}
}
}
}
}
}
return res
}
@@ -0,0 +1,56 @@
// FILE: test.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// suspend calls possible inside lambda matching to the parameter
suspend inline fun test(c: () -> Unit) {
c()
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
inline fun transform(crossinline c: suspend () -> Unit) {
builder { c() }
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
suspend fun calculate() = "OK"
fun box() : String {
var res = "FAIL 1"
builder {
test {
res = calculate()
}
}
if (res != "OK") return res
builder {
test {
transform {
test {
res = calculate()
}
}
}
}
return res
}
@@ -0,0 +1,57 @@
// FILE: test.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// suspend calls possible inside lambda matching to the parameter
suspend inline fun test(c: suspend () -> Unit) {
c()
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun calculate() = "OK"
fun box() : String {
var res = "FAIL 1"
builder {
test {
res = calculate()
}
}
if (res != "OK") return res
res = "FAIL 2"
builder {
test {
test {
test {
test {
test {
res = calculate()
}
}
}
}
}
}
return res
}
@@ -0,0 +1,123 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
object Result {
var a: String = ""
var b: Int = 0
}
suspend inline fun inlineMe(c: suspend () -> Unit) {
var a = ""
var b = 0
val r = object: Runnable {
override fun run() {
b++
a += "a"
}
}
r.run()
c()
r.run()
Result.a = a
Result.b = b
}
suspend inline fun noinlineMe(noinline c: suspend () -> Unit) {
var a = ""
var b = 0
val r = object: Runnable {
override fun run() {
b += 2
a += "b"
}
}
r.run()
c()
r.run()
Result.a += a
Result.b += b
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
var a = ""
var b = 0
val r = object: Runnable {
override fun run() {
b += 3
a += "c"
}
}
r.run()
c()
r.run()
Result.a += a
Result.b += b
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun dummy() {
val local0 = 0
val local1 = 0
val local2 = 0
val local3 = 0
val local4 = 0
val local5 = 0
val local6 = 0
val local7 = 0
val local8 = 0
val local9 = 0
val local10 = 0
val local11 = 0
val local12 = 0
val local13 = 0
val local14 = 0
val local15 = 0
val local16 = 0
val local17 = 0
val local18 = 0
val local19 = 0
val local20 = 0
val local21 = 0
val local22 = 0
}
suspend fun inlineSite() {
inlineMe {
dummy()
dummy()
}
if (Result.a != "aa" || Result.b != 2) throw RuntimeException("FAIL 1")
noinlineMe {
dummy()
dummy()
}
if (Result.a != "aabb" || Result.b != 6) throw RuntimeException("FAIL 2")
crossinlineMe {
dummy()
dummy()
}
if (Result.a != "aabbcc" || Result.b != 12) throw RuntimeException("FAIL 3")
}
fun box(): String {
builder {
inlineSite()
}
return "OK"
}
@@ -0,0 +1,84 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
suspend inline fun inlineMe(c: suspend () -> Unit) {
c()
c()
c()
c()
c()
}
suspend inline fun noinlineMe(noinline c: suspend () -> Unit) {
c()
c()
c()
c()
c()
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
c()
c()
c()
c()
c()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
var j = 0;
var k = 0;
suspend fun calculateI() {
i++
}
suspend fun calculateJ() {
j++
}
suspend fun calculateK() {
k++
}
suspend fun inlineSite() {
inlineMe {
calculateI()
calculateI()
}
noinlineMe {
calculateJ()
calculateJ()
}
crossinlineMe {
calculateK()
calculateK()
}
}
fun box(): String {
builder {
inlineSite()
}
if (i != 10) return "FAIL I"
if (j != 10) return "FAIL J"
if (k != 10) return "FAIL K"
return "OK"
}
@@ -0,0 +1,105 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// Are suspend calls possible inside lambda matching to the parameter
interface SuspendRunnable {
suspend fun run()
}
class Controller {
var res = "FAIL 1"
inline fun test1(crossinline runner: suspend Controller.() -> Unit) {
val l : suspend Controller.() -> Unit = { runner() }
builder(this) { l() }
}
inline fun test2(crossinline c: suspend Controller.() -> Unit) {
val sr = object: SuspendRunnable {
override suspend fun run() {
c()
}
}
builder(this) { sr.run() }
}
}
fun builder(controller: Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
suspend fun calculate() = "OK"
fun box(): String {
val controller = Controller()
controller.test1 {
res = calculate()
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 2"
controller.test1 {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 3"
controller.test2 {
res = calculate()
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 4"
controller.test2 {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 5"
controller.test1 {
test2 {
test1 {
test2 {
test1 {
test2 {
res = calculate()
}
}
}
}
}
}
return controller.res
}
@@ -0,0 +1,132 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// Start coroutine call is possible
// Are suspend calls possible inside lambda matching to the parameter
interface SuspendRunnable {
suspend fun run()
}
val EmptyContinuation = object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
}
class Controller {
var res = "FAIL 1"
inline fun test1(noinline c: suspend Controller.() -> Unit) {
val l : suspend Controller.() -> Unit = { c() }
builder(this) { l() }
}
inline fun test2(noinline c: suspend Controller.() -> Unit) {
c.startCoroutine(this, EmptyContinuation)
}
inline fun test3(noinline c: suspend Controller.() -> Unit) {
val sr = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
builder(this) { sr.run() }
}
}
fun builder(controller: Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, EmptyContinuation)
}
// FILE: box.kt
suspend fun calculate() = "OK"
fun box(): String {
val controller = Controller()
controller.test1 {
res = calculate()
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 2"
controller.test2 {
res = "OK"
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 3"
controller.test3 {
res = "OK"
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 4"
controller.test1 {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 5"
controller.test2 {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 6"
controller.test3 {
test3 {
test3 {
test3 {
test3 {
test3 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 7"
controller.test1 {
test2 {
test3 {
test1 {
test2 {
test3 {
res = calculate()
}
}
}
}
}
}
return controller.res
}
@@ -0,0 +1,113 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
class Controller {
var res = "FAIL 1"
suspend inline fun test1(crossinline c: Controller.() -> Unit) {
c()
}
suspend inline fun test2(crossinline c: Controller.() -> Unit) {
val l = { c() }
l()
}
suspend inline fun test3(crossinline c: Controller.() -> Unit) {
val r = object: Runnable {
override fun run() {
c()
}
}
r.run()
}
inline fun transform(crossinline c: suspend Controller.() -> Unit) {
builder(this) { c() }
}
}
fun builder(controller : Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun box() : String {
val controller = Controller()
builder(controller) {
test1 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 2"
builder(controller) {
test2 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 3"
builder(controller) {
test3 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 4"
builder(controller) {
test1 {
transform {
test1 {
res = "OK"
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 5"
builder(controller) {
test2 {
transform {
test2 {
res = "OK"
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 6"
builder(controller) {
test3 {
transform {
test3 {
res = "OK"
}
}
}
}
return controller.res
}
@@ -0,0 +1,138 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// suspend calls possible inside lambda matching to the parameter
interface SuspendRunnable {
suspend fun run()
}
class Controller {
var res = "FAIL 1"
suspend inline fun test1(crossinline c: suspend Controller.() -> Unit) {
c()
}
suspend inline fun test2(crossinline c: suspend Controller.() -> Unit) {
val l: suspend Controller.() -> Unit = { c() }
l()
}
suspend inline fun test3(crossinline c: suspend Controller.() -> Unit) {
val sr = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
sr.run()
}
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun builder(controller: Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun calculate() = "OK"
fun box() : String {
val controller = Controller()
builder(controller) {
test1 {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 2"
builder(controller) {
test2 {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 3"
builder(controller) {
test3 {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 4"
builder(controller) {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 5"
builder(controller) {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 6"
builder(controller) {
test3 {
test3 {
test3 {
test3 {
test3 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 7"
builder(controller) {
test1 {
test2 {
test3 {
test1 {
test2 {
res = calculate()
}
}
}
}
}
}
return controller.res
}
@@ -0,0 +1,113 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
class Controller {
var res = "FAIL 1"
suspend inline fun test1(noinline c: Controller.() -> Unit) {
c()
}
suspend inline fun test2(noinline c: Controller.() -> Unit) {
val l = { c() }
l()
}
suspend inline fun test3(noinline c: Controller.() -> Unit) {
val r = object: Runnable {
override fun run() {
c()
}
}
r.run()
}
inline fun transform(crossinline c: suspend Controller.() -> Unit) {
builder(this) { c() }
}
}
fun builder(controller: Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun box() : String {
val controller = Controller()
builder(controller) {
test1 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 2"
builder(controller) {
test2 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 3"
builder(controller) {
test3 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 4"
builder(controller) {
test1 {
transform {
test1 {
res = "OK"
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 5"
builder(controller) {
test2 {
transform {
test2 {
res = "OK"
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 6"
builder(controller) {
test3 {
transform {
test3 {
res = "OK"
}
}
}
}
return controller.res
}
@@ -0,0 +1,167 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// Are suspend calls possible inside lambda matching to the parameter
// Start coroutine call is possible
// Block is allowed to be called directly inside inline function
interface SuspendRunnable {
suspend fun run()
}
object EmptyContinuation: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
}
class Controller {
var res = "FAIL 1"
suspend inline fun test1(noinline c: suspend Controller.() -> Unit) {
val l : suspend Controller.() -> Unit = { c() }
l()
}
suspend inline fun test2(noinline c: suspend Controller.() -> Unit) {
c.startCoroutine(this, EmptyContinuation)
}
suspend inline fun test3(noinline c: suspend Controller.() -> Unit) {
c()
}
suspend inline fun test4(noinline c: suspend Controller.() -> Unit) {
val sr = object: SuspendRunnable {
override suspend fun run() {
c()
}
}
sr.run()
}
}
fun builder(controller: Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, EmptyContinuation)
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
suspend fun calculate() = "OK"
fun box(): String {
val controller = Controller()
builder(controller) {
test1 {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 2"
builder(controller) {
test2 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 3"
builder(controller) {
test3 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 4"
builder(controller) {
test4 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 5"
builder(controller) {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 6"
builder(controller) {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 7"
builder(controller) {
test3 {
test3 {
test3 {
test3 {
test3 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 8"
builder(controller) {
test4 {
test4 {
test4 {
test4 {
test4 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 9"
builder(controller) {
test1 {
test2 {
test3 {
test4 {
test1 {
res = calculate()
}
}
}
}
}
}
return controller.res
}
@@ -0,0 +1,60 @@
// FILE: test.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// suspend calls possible inside lambda matching to the parameter
class Controller {
var res = "FAIL 1"
suspend inline fun test(c: Controller.() -> Unit) {
c()
}
inline fun transform(crossinline c: suspend Controller.() -> Unit) {
builder(this) { c() }
}
}
fun builder(controller: Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
suspend fun calculate() = "OK"
fun box() : String {
val controller = Controller()
builder(controller) {
test {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
builder(controller) {
test {
transform {
test {
res = calculate()
}
}
}
}
return controller.res
}
@@ -0,0 +1,61 @@
// FILE: test.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// suspend calls possible inside lambda matching to the parameter
class Controller {
var res = "FAIL 1"
suspend inline fun test(c: suspend Controller.() -> Unit) {
c()
}
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun builder(controller: Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun calculate() = "OK"
fun box() : String {
val controller = Controller()
builder(controller) {
test {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 2"
builder(controller) {
test {
test {
test {
test {
test {
res = calculate()
}
}
}
}
}
}
return controller.res
}
@@ -0,0 +1,48 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = { c() }
l()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
fun box(): String {
builder {
crossinlineMe {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
if (i != 1) return "FAIL"
return "OK"
}
@@ -0,0 +1,53 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = {
val l1 : suspend () -> Unit = {
c()
}
l1()
}
l()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
fun box(): String {
builder {
crossinlineMe {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
if (i != 1) return "FAIL $i"
return "OK"
}
@@ -0,0 +1,52 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.intrinsics.*
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
l()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
fun box(): String {
var res = "OK"
builder {
crossinlineMe {
res = "FAIL 1"
}
}
if (i != 1) return "FAIL 2"
return res
}
@@ -0,0 +1,75 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = {
val sr = object: SuspendRunnable {
override suspend fun run() {
val l : suspend () -> Unit = {
val sr = object: SuspendRunnable {
override suspend fun run() {
val l : suspend () -> Unit = {
val sr = object: SuspendRunnable {
override suspend fun run() {
c()
}
}
sr.run()
}
l()
}
}
sr.run()
}
l()
}
}
sr.run()
}
l()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
fun box(): String {
builder {
crossinlineMe {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
if (i != 1) return "FAIL $i"
return "OK"
}
@@ -0,0 +1,75 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = {
c()
}
l()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
fun box(): String {
builder {
crossinlineMe {
val sr = object: SuspendRunnable {
override suspend fun run() {
val l : suspend () -> Unit = {
val sr = object: SuspendRunnable {
override suspend fun run() {
val l : suspend () -> Unit = {
val sr = object: SuspendRunnable {
override suspend fun run() {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
sr.run()
}
l()
}
}
sr.run()
}
l()
}
}
sr.run()
}
}
if (i != 1) return "FAIL $i"
return "OK"
}
@@ -0,0 +1,56 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val o = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
o.run()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
fun box(): String {
builder {
crossinlineMe {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
if (i != 1) return "FAIL $i"
return "OK"
}
@@ -0,0 +1,61 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val o = object : SuspendRunnable {
override suspend fun run() {
val o1 = object: SuspendRunnable {
override suspend fun run() {
c()
}
}
o1.run()
}
}
o.run()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
fun box(): String {
builder {
crossinlineMe {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
if (i != 1) return "FAIL $i"
return "OK"
}
@@ -0,0 +1,60 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
interface SuspendRunnable {
suspend fun run1()
suspend fun run2()
}
suspend inline fun crossinlineMe(crossinline c1: suspend () -> Unit, crossinline c2: suspend () -> Unit) {
val o = object : SuspendRunnable {
override suspend fun run1() {
c1()
}
override suspend fun run2() {
c2()
}
}
o.run1()
o.run2()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
var j = 0;
suspend fun incrementI() {
i++
}
suspend fun incrementJ() {
j++
}
fun box(): String {
builder {
crossinlineMe({ incrementI() }) { incrementJ() }
}
if (i != 1) return "FAIL i $i"
if (j != 1) return "FAIL i $i"
return "OK"
}
@@ -0,0 +1,58 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.intrinsics.*
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val o = object : SuspendRunnable {
override suspend fun run() {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
o.run()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
fun box(): String {
var res = "OK"
builder {
crossinlineMe {
res = "FAIL 1"
}
}
if (i != 1) return "FAIL 2"
return res
}
@@ -0,0 +1,48 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
c()
c()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
fun box(): String {
builder {
crossinlineMe {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
if (i != 1) return "FAIL"
return "OK"
}
@@ -0,0 +1,68 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = { c() }
l()
}
suspend inline fun crossinlineMe2(crossinline c: suspend () -> Unit) {
crossinlineMe { c(); c() }
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
var result = "FAIL"
var i = 0
var finished = false
var proceed: () -> Unit = {}
suspend fun suspendHere() = suspendCoroutine<Unit> { c ->
i++
proceed = { c.resume(Unit) }
}
fun builder(c: suspend () -> Unit) {
val continuation = object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
proceed = {
result = "OK"
finished = true
}
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
}
c.startCoroutine(continuation)
}
fun box(): String {
builder {
crossinlineMe2 {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
for (counter in 0 until 10) {
if (i != counter + 1) return "Expected ${counter + 1}, got $i"
proceed()
}
if (i != 10) return "FAIL $i"
if (finished) return "resume on root continuation is called"
proceed()
if (!finished) return "resume on root continuation is not called"
return result
}
@@ -0,0 +1,84 @@
// FILE: inlined.kt
// WITH_RUNTIME
// 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
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
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"
}