Implement coroutineContext intrinsic

This intrinsic allows coroutine to access its context without suspention
and, furthermore, disabling tail-call optimization.
KT-17609: Fixed
This commit is contained in:
Ilmir Usmanov
2017-10-23 13:38:23 +03:00
parent 0fffb9fb17
commit 817f79520a
28 changed files with 520 additions and 35 deletions
@@ -0,0 +1,42 @@
// WITH_RUNTIME
// WITH_COROUTINES
import helpers.*
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
import kotlin.test.assertEquals
suspend fun suspendHere() = if(coroutineContext != EmptyCoroutineContext) "$coroutineContext != $EmptyCoroutineContext" else "OK"
suspend fun multipleArgs(a: Any, b: Any, c: Any) = if(coroutineContext != EmptyCoroutineContext) "$coroutineContext != $EmptyCoroutineContext" else "OK"
fun builder(c: suspend () -> String): String {
var fromSuspension: String? = null
val continuation = object: Continuation<String> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resumeWithException(exception: Throwable) {
fromSuspension = "Exception: ${exception}"
}
override fun resume(value: String) {
fromSuspension = value
}
}
c.startCoroutine(continuation)
return fromSuspension as String
}
fun box(): String {
var res = builder { suspendHere() }
if (res != "OK") { return "fail 1 $res"}
res = builder { multipleArgs(1,1,1) }
if (res != "OK") { return "fail 2 $res"}
res = builder { if(coroutineContext != EmptyCoroutineContext) "$coroutineContext != $EmptyCoroutineContext" else "OK" }
if (res != "OK") { return "fail 3 $res"}
return "OK"
}
@@ -0,0 +1,43 @@
// WITH_RUNTIME
// WITH_COROUTINES
import helpers.*
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
import kotlin.test.assertEquals
class Controller {
suspend fun controllerSuspendHere() = if(coroutineContext != EmptyCoroutineContext) "$coroutineContext != $EmptyCoroutineContext" else "OK"
suspend fun controllerMultipleArgs(a: Any, b: Any, c: Any) = if(coroutineContext != EmptyCoroutineContext) "$coroutineContext != $EmptyCoroutineContext" else "OK"
fun builder(c: suspend Controller.() -> String): String {
var fromSuspension: String? = null
c.startCoroutine(this, object: Continuation<String> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resumeWithException(exception: Throwable) {
fromSuspension = "Exception: " + exception.message!!
}
override fun resume(value: String) {
fromSuspension = value
}
})
return fromSuspension as String
}
}
fun box(): String {
val c = Controller()
var res = c.builder { controllerSuspendHere() }
if (res != "OK") { return "fail 1 $res"}
res = c.builder { controllerMultipleArgs(1,1,1) }
if (res != "OK") { return "fail 2 $res"}
res = c.builder { if(coroutineContext != EmptyCoroutineContext) "$coroutineContext != $EmptyCoroutineContext" else "OK" }
if (res != "OK") { return "fail 3 $res"}
return "OK"
}
@@ -0,0 +1,59 @@
// WITH_RUNTIME
// WITH_COROUTINES
import helpers.*
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
import kotlin.test.assertEquals
class Controller {
val coroutineContext = object : CoroutineContext {
public override fun <E : CoroutineContext.Element> get(key: CoroutineContext.Key<E>): E? = null
public override fun <R> fold(initial: R, operation: (R, CoroutineContext.Element) -> R): R = initial
public override fun plus(context: CoroutineContext): CoroutineContext = context
public override fun minusKey(key: CoroutineContext.Key<*>): CoroutineContext = this
public override fun hashCode(): Int = 0
public override fun toString(): String = "AnotherEmptyCoroutineContext"
}
suspend fun controllerSuspendHere() = if(coroutineContext == EmptyCoroutineContext) "$coroutineContext == $EmptyCoroutineContext" else "OK"
suspend fun controllerSuspendHereIntrinsic() = if(kotlin.coroutines.experimental.intrinsics.coroutineContext != EmptyCoroutineContext)
"${kotlin.coroutines.experimental.intrinsics.coroutineContext} != $EmptyCoroutineContext"
else
"OK"
suspend fun controllerMultipleArgs(a: Any, b: Any, c: Any) = if(coroutineContext == EmptyCoroutineContext) "$coroutineContext == $EmptyCoroutineContext" else "OK"
fun builder(c: suspend Controller.() -> String): String {
var fromSuspension: String? = null
c.startCoroutine(this, object: Continuation<String> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resumeWithException(exception: Throwable) {
fromSuspension = "Exception: " + exception.message!!
}
override fun resume(value: String) {
fromSuspension = value
}
})
return fromSuspension as String
}
}
fun box(): String {
val v = Controller()
var res = v.builder { controllerMultipleArgs(1,1,1) }
if (res != "OK") { return "fail 1 $res"}
res = v.builder { if(coroutineContext == EmptyCoroutineContext) "$coroutineContext == $EmptyCoroutineContext" else "OK" }
if (res != "OK") { return "fail 2 $res"}
res = v.builder { controllerSuspendHereIntrinsic() }
if (res != "OK") { return "fail 3 $res"}
res = v.builder { controllerSuspendHere() }
if (res != "OK") { return "fail 4 $res"}
return "OK"
}
@@ -0,0 +1,18 @@
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
suspend fun suspendHere(ctx: CoroutineContext) = suspendCoroutineOrReturn<String> { x ->
if (x.context == ctx) x.resume("OK") else x.resume("FAIL")
}
suspend fun mustBeTailCall(): String {
return suspendHere(coroutineContext)
}
suspend fun retrieveCoroutineContext(): CoroutineContext =
suspendCoroutineOrReturn { cont -> cont.context }
suspend fun notTailCall(): String {
return suspendHere(retrieveCoroutineContext())
}
@@ -0,0 +1,19 @@
@kotlin.Metadata
final class CoroutineContextIntrinsicKt$notTailCall$1 {
synthetic field data: java.lang.Object
synthetic field exception: java.lang.Throwable
inner class CoroutineContextIntrinsicKt$notTailCall$1
method <init>(p0: kotlin.coroutines.experimental.Continuation): void
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
synthetic final method getLabel(): int
synthetic final method setLabel(p0: int): void
}
@kotlin.Metadata
public final class CoroutineContextIntrinsicKt {
inner class CoroutineContextIntrinsicKt$notTailCall$1
public final static @org.jetbrains.annotations.Nullable method mustBeTailCall(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
public final static @org.jetbrains.annotations.Nullable method notTailCall(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
public final static @org.jetbrains.annotations.Nullable method retrieveCoroutineContext(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
public final static @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.CoroutineContext, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
}