Promote CoroutineStart.UNDISPATCHED to non experimental API (#2505)
Fixes #1393
diff --git a/kotlinx-coroutines-core/common/src/CoroutineStart.kt b/kotlinx-coroutines-core/common/src/CoroutineStart.kt
index c9be183..6059829 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineStart.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineStart.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -58,8 +58,8 @@
ATOMIC,
/**
- * Immediately executes the coroutine until its first suspension point _in the current thread_ as if the
- * coroutine was started using [Dispatchers.Unconfined]. However, when the coroutine is resumed from suspension
+ * Immediately executes the coroutine until its first suspension point _in the current thread_ similarly to
+ * the coroutine being started using [Dispatchers.Unconfined]. However, when the coroutine is resumed from suspension
* it is dispatched according to the [CoroutineDispatcher] in its context.
*
* This is similar to [ATOMIC] in the sense that coroutine starts executing even if it was already cancelled,
@@ -68,9 +68,11 @@
* Cancellability of coroutine at suspension points depends on the particular implementation details of
* suspending functions as in [DEFAULT].
*
- * **Note: This is an experimental api.** Execution semantics of coroutines may change in the future when this mode is used.
+ * ### Unconfined event loop
+ *
+ * Unlike [Dispatchers.Unconfined] and [MainCoroutineDispatcher.immediate], nested undispatched coroutines do not form
+ * an event loop that otherwise prevents potential stack overflow in case of unlimited nesting.
*/
- @ExperimentalCoroutinesApi // Since 1.0.0, no ETA on stability
UNDISPATCHED;
/**
diff --git a/kotlinx-coroutines-core/common/test/AtomicCancellationCommonTest.kt b/kotlinx-coroutines-core/common/test/AtomicCancellationCommonTest.kt
index c763faf..a410137 100644
--- a/kotlinx-coroutines-core/common/test/AtomicCancellationCommonTest.kt
+++ b/kotlinx-coroutines-core/common/test/AtomicCancellationCommonTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
@@ -32,6 +32,38 @@
}
@Test
+ fun testUndispatchedLaunch() = runTest {
+ expect(1)
+ assertFailsWith<CancellationException> {
+ withContext(Job()) {
+ cancel()
+ launch(start = CoroutineStart.UNDISPATCHED) {
+ expect(2)
+ yield()
+ expectUnreached()
+ }
+ }
+ }
+ finish(3)
+ }
+
+ @Test
+ fun testUndispatchedLaunchWithUnconfinedContext() = runTest {
+ expect(1)
+ assertFailsWith<CancellationException> {
+ withContext(Dispatchers.Unconfined + Job()) {
+ cancel()
+ launch(start = CoroutineStart.UNDISPATCHED) {
+ expect(2)
+ yield()
+ expectUnreached()
+ }
+ }
+ }
+ finish(3)
+ }
+
+ @Test
fun testDeferredAwaitCancellable() = runTest {
expect(1)
val deferred = async { // deferred, not yet complete
@@ -122,4 +154,4 @@
yield() // now yield
finish(4)
}
-}
\ No newline at end of file
+}