Skip to content

Commit b058ba1

Browse files
committed
Deprecate Job.cancel(cause) and ReceiveChannel.cancel(cause), return Unit from cancel without cause
Fixes #713 Fixes #481
1 parent 23d435b commit b058ba1

File tree

18 files changed

+118
-105
lines changed

18 files changed

+118
-105
lines changed

binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public abstract interface class kotlinx/coroutines/ChildJob : kotlinx/coroutines
7676
}
7777

7878
public final class kotlinx/coroutines/ChildJob$DefaultImpls {
79+
public static synthetic fun cancel (Lkotlinx/coroutines/ChildJob;)Z
7980
public static fun fold (Lkotlinx/coroutines/ChildJob;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
8081
public static fun get (Lkotlinx/coroutines/ChildJob;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
8182
public static fun minusKey (Lkotlinx/coroutines/ChildJob;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
@@ -89,6 +90,7 @@ public abstract interface class kotlinx/coroutines/CompletableDeferred : kotlinx
8990
}
9091

9192
public final class kotlinx/coroutines/CompletableDeferred$DefaultImpls {
93+
public static synthetic fun cancel (Lkotlinx/coroutines/CompletableDeferred;)Z
9294
public static fun fold (Lkotlinx/coroutines/CompletableDeferred;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
9395
public static fun get (Lkotlinx/coroutines/CompletableDeferred;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
9496
public static fun minusKey (Lkotlinx/coroutines/CompletableDeferred;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
@@ -197,6 +199,7 @@ public abstract interface class kotlinx/coroutines/Deferred : kotlinx/coroutines
197199
}
198200

199201
public final class kotlinx/coroutines/Deferred$DefaultImpls {
202+
public static synthetic fun cancel (Lkotlinx/coroutines/Deferred;)Z
200203
public static fun fold (Lkotlinx/coroutines/Deferred;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
201204
public static fun get (Lkotlinx/coroutines/Deferred;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
202205
public static fun minusKey (Lkotlinx/coroutines/Deferred;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
@@ -260,7 +263,8 @@ public abstract interface annotation class kotlinx/coroutines/InternalCoroutines
260263
public abstract interface class kotlinx/coroutines/Job : kotlin/coroutines/CoroutineContext$Element {
261264
public static final field Key Lkotlinx/coroutines/Job$Key;
262265
public abstract fun attachChild (Lkotlinx/coroutines/ChildJob;)Lkotlinx/coroutines/ChildHandle;
263-
public abstract fun cancel ()Z
266+
public abstract fun cancel ()V
267+
public abstract synthetic fun cancel ()Z
264268
public abstract fun cancel (Ljava/lang/Throwable;)Z
265269
public abstract fun getCancellationException ()Ljava/util/concurrent/CancellationException;
266270
public abstract fun getChildren ()Lkotlin/sequences/Sequence;
@@ -276,6 +280,7 @@ public abstract interface class kotlinx/coroutines/Job : kotlin/coroutines/Corou
276280
}
277281

278282
public final class kotlinx/coroutines/Job$DefaultImpls {
283+
public static synthetic fun cancel (Lkotlinx/coroutines/Job;)Z
279284
public static synthetic fun cancel$default (Lkotlinx/coroutines/Job;Ljava/lang/Throwable;ILjava/lang/Object;)Z
280285
public static fun fold (Lkotlinx/coroutines/Job;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
281286
public static fun get (Lkotlinx/coroutines/Job;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
@@ -292,12 +297,14 @@ public final class kotlinx/coroutines/JobKt {
292297
public static final fun DisposableHandle (Lkotlin/jvm/functions/Function0;)Lkotlinx/coroutines/DisposableHandle;
293298
public static final fun Job (Lkotlinx/coroutines/Job;)Lkotlinx/coroutines/Job;
294299
public static synthetic fun Job$default (Lkotlinx/coroutines/Job;ILjava/lang/Object;)Lkotlinx/coroutines/Job;
295-
public static final fun cancel (Lkotlin/coroutines/CoroutineContext;)Z
300+
public static final fun cancel (Lkotlin/coroutines/CoroutineContext;)V
301+
public static final synthetic fun cancel (Lkotlin/coroutines/CoroutineContext;)Z
296302
public static final fun cancel (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Throwable;)Z
297303
public static synthetic fun cancel$default (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Throwable;ILjava/lang/Object;)Z
298304
public static final fun cancelAndJoin (Lkotlinx/coroutines/Job;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
299305
public static final fun cancelChildren (Lkotlin/coroutines/CoroutineContext;)V
300306
public static final fun cancelChildren (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Throwable;)V
307+
public static final fun cancelChildren (Lkotlinx/coroutines/Job;)V
301308
public static final fun cancelChildren (Lkotlinx/coroutines/Job;Ljava/lang/Throwable;)V
302309
public static synthetic fun cancelChildren$default (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Throwable;ILjava/lang/Object;)V
303310
public static synthetic fun cancelChildren$default (Lkotlinx/coroutines/Job;Ljava/lang/Throwable;ILjava/lang/Object;)V
@@ -309,7 +316,8 @@ public final class kotlinx/coroutines/JobKt {
309316
public class kotlinx/coroutines/JobSupport : kotlinx/coroutines/ChildJob, kotlinx/coroutines/Job, kotlinx/coroutines/ParentJob, kotlinx/coroutines/selects/SelectClause0 {
310317
public fun <init> (Z)V
311318
public final fun attachChild (Lkotlinx/coroutines/ChildJob;)Lkotlinx/coroutines/ChildHandle;
312-
public fun cancel ()Z
319+
public fun cancel ()V
320+
public synthetic fun cancel ()Z
313321
public fun cancel (Ljava/lang/Throwable;)Z
314322
public fun childCancelled (Ljava/lang/Throwable;)Z
315323
public fun fold (Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
@@ -349,7 +357,8 @@ public abstract class kotlinx/coroutines/MainCoroutineDispatcher : kotlinx/corou
349357
public final class kotlinx/coroutines/NonCancellable : kotlin/coroutines/AbstractCoroutineContextElement, kotlinx/coroutines/Job {
350358
public static final field INSTANCE Lkotlinx/coroutines/NonCancellable;
351359
public fun attachChild (Lkotlinx/coroutines/ChildJob;)Lkotlinx/coroutines/ChildHandle;
352-
public fun cancel ()Z
360+
public fun cancel ()V
361+
public synthetic fun cancel ()Z
353362
public fun cancel (Ljava/lang/Throwable;)Z
354363
public fun getCancellationException ()Ljava/util/concurrent/CancellationException;
355364
public fun getChildren ()Lkotlin/sequences/Sequence;
@@ -379,6 +388,7 @@ public abstract interface class kotlinx/coroutines/ParentJob : kotlinx/coroutine
379388
}
380389

381390
public final class kotlinx/coroutines/ParentJob$DefaultImpls {
391+
public static synthetic fun cancel (Lkotlinx/coroutines/ParentJob;)Z
382392
public static fun fold (Lkotlinx/coroutines/ParentJob;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
383393
public static fun get (Lkotlinx/coroutines/ParentJob;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
384394
public static fun minusKey (Lkotlinx/coroutines/ParentJob;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
@@ -439,6 +449,10 @@ public abstract interface class kotlinx/coroutines/channels/ActorScope : kotlinx
439449
public abstract fun getChannel ()Lkotlinx/coroutines/channels/Channel;
440450
}
441451

452+
public final class kotlinx/coroutines/channels/ActorScope$DefaultImpls {
453+
public static synthetic fun cancel (Lkotlinx/coroutines/channels/ActorScope;)Z
454+
}
455+
442456
public abstract interface class kotlinx/coroutines/channels/BroadcastChannel : kotlinx/coroutines/channels/SendChannel {
443457
public abstract fun cancel (Ljava/lang/Throwable;)Z
444458
public abstract fun openSubscription ()Lkotlinx/coroutines/channels/ReceiveChannel;
@@ -466,6 +480,10 @@ public abstract interface class kotlinx/coroutines/channels/Channel : kotlinx/co
466480
public static final field UNLIMITED I
467481
}
468482

483+
public final class kotlinx/coroutines/channels/Channel$DefaultImpls {
484+
public static synthetic fun cancel (Lkotlinx/coroutines/channels/Channel;)Z
485+
}
486+
469487
public final class kotlinx/coroutines/channels/Channel$Factory {
470488
public static final field CONFLATED I
471489
public static final field RENDEZVOUS I
@@ -637,7 +655,8 @@ public abstract interface class kotlinx/coroutines/channels/ProducerScope : kotl
637655
}
638656

639657
public abstract interface class kotlinx/coroutines/channels/ReceiveChannel {
640-
public abstract fun cancel ()Z
658+
public abstract fun cancel ()V
659+
public abstract synthetic fun cancel ()Z
641660
public abstract fun cancel (Ljava/lang/Throwable;)Z
642661
public abstract fun getOnReceive ()Lkotlinx/coroutines/selects/SelectClause1;
643662
public abstract fun getOnReceiveOrNull ()Lkotlinx/coroutines/selects/SelectClause1;
@@ -650,6 +669,7 @@ public abstract interface class kotlinx/coroutines/channels/ReceiveChannel {
650669
}
651670

652671
public final class kotlinx/coroutines/channels/ReceiveChannel$DefaultImpls {
672+
public static synthetic fun cancel (Lkotlinx/coroutines/channels/ReceiveChannel;)Z
653673
public static synthetic fun cancel$default (Lkotlinx/coroutines/channels/ReceiveChannel;Ljava/lang/Throwable;ILjava/lang/Object;)Z
654674
}
655675

common/kotlinx-coroutines-core-common/src/Job.kt

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
@file:JvmMultifileClass
66
@file:JvmName("JobKt")
7-
@file:Suppress("DEPRECATION_ERROR")
7+
@file:Suppress("DEPRECATION_ERROR", "RedundantUnitReturnType")
88

99
package kotlinx.coroutines
1010

@@ -154,29 +154,27 @@ public interface Job : CoroutineContext.Element {
154154
*/
155155
public fun start(): Boolean
156156

157+
/**
158+
* @suppress
159+
*/
160+
@Suppress("INAPPLICABLE_JVM_NAME")
161+
@Deprecated(level = DeprecationLevel.HIDDEN, message = "Left here for binary compatibility")
162+
@JvmName("cancel")
163+
public fun cancel0(): Boolean = cancel(null)
164+
157165
/**
158166
* Cancels this job.
159-
* The result is `true` if this job was either cancelled as a result of this invocation
160-
* or was already being cancelled.
161-
* If job is already completed, method returns `false`.
167+
* See [Job] documentation for full explanation of cancellation machinery.
162168
*/
163-
public fun cancel(): Boolean
169+
public fun cancel(): Unit
164170

165171
/**
166-
* Cancels this job with an optional cancellation [cause].
167-
* The result is `true` if this job was either cancelled as a result of this invocation
168-
* or it's being cancelled and given [cause] was successfully received by the job and will be properly handled, `false` otherwise.
169-
*
170-
* If this method returned `false`, then caller is responsible for handling [cause].
171-
* If job is already completed, method returns `false`.
172-
*
173-
* When cancellation has a clear reason in the code, an instance of [CancellationException] should be created
174-
* at the corresponding original cancellation site and passed into this method to aid in debugging by providing
175-
* both the context of cancellation and text description of the reason.
176-
*
177-
* **Note: This is an experimental api.** Cancellation of a job with exception may change its semantics in the future.
172+
* @suppress
178173
*/
179-
@ExperimentalCoroutinesApi
174+
@ObsoleteCoroutinesApi
175+
@Deprecated(level = DeprecationLevel.WARNING, message = "Use CompletableDeferred.completeExceptionally(cause) or Job.cancel() instead",
176+
replaceWith = ReplaceWith("cancel()")
177+
)
180178
public fun cancel(cause: Throwable? = null): Boolean
181179

182180
// ------------ parent-child ------------
@@ -470,14 +468,22 @@ public suspend fun Job.cancelAndJoin() {
470468
}
471469

472470
/**
473-
* Cancels all [children][Job.children] jobs of this coroutine with the given [cause] using [Job.cancel]
474-
* for all of them. Unlike [Job.cancel] on this job as a whole, the state of this job itself is not affected.
471+
* @suppress
475472
*/
476-
@Suppress("EXTENSION_SHADOWED_BY_MEMBER") // See KT-21598
473+
@ObsoleteCoroutinesApi
474+
@Deprecated(level = DeprecationLevel.WARNING, message = "Use cancelChildren() without cause", replaceWith = ReplaceWith("cancelChildren()"))
477475
public fun Job.cancelChildren(cause: Throwable? = null) {
478476
children.forEach { it.cancel(cause) }
479477
}
480478

479+
/**
480+
* Cancels all [children][Job.children] jobs of this coroutine using [Job.cancel] for all of them.
481+
* Unlike [Job.cancel] on this job as a whole, the state of this job itself is not affected.
482+
*/
483+
public fun Job.cancelChildren() {
484+
children.forEach { it.cancel() }
485+
}
486+
481487
// -------------------- CoroutineContext extensions --------------------
482488

483489
/**
@@ -499,22 +505,29 @@ public fun Job.cancelChildren(cause: Throwable? = null) {
499505
public val CoroutineContext.isActive: Boolean
500506
get() = this[Job]?.isActive == true
501507

508+
502509
/**
503-
* Cancels [Job] of this context. The result is `true` if the job was
504-
* cancelled as a result of this invocation or was already being cancelled and
505-
* `false` if there is no job in the context or if it was already completed. See [Job.cancel] for details.
510+
* @suppress
506511
*/
507-
public fun CoroutineContext.cancel(): Boolean =
508-
this[Job]?.cancel() ?: false
512+
@JvmName("cancel")
513+
@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
514+
public fun CoroutineContext.cancel0(): Boolean {
515+
this[Job]?.cancel()
516+
return true
517+
}
509518

510519
/**
511-
* Cancels [Job] of this context with an optional cancellation [cause]. The result is `true` if the job was
512-
* cancelled as a result of this invocation and `false` if there is no job in the context or if it was already
513-
* cancelled or completed. See [Job.cancel] for details.
514-
*
515-
* **Note: This is an experimental api.** Cancellation of a job with exception may change its semantics in the future.
520+
* Cancels [Job] of this context. See [Job.cancel] for details.
516521
*/
517-
@ExperimentalCoroutinesApi
522+
public fun CoroutineContext.cancel(): Unit {
523+
this[Job]?.cancel()
524+
}
525+
526+
/**
527+
* @suppress
528+
*/
529+
@ObsoleteCoroutinesApi
530+
@Deprecated(level = DeprecationLevel.WARNING, message = "Use cancel() without cause", replaceWith = ReplaceWith("cancel()"))
518531
public fun CoroutineContext.cancel(cause: Throwable? = null): Boolean =
519532
this[Job]?.cancel(cause) ?: false
520533

@@ -526,14 +539,8 @@ public fun CoroutineContext.cancelChildren() {
526539
this[Job]?.children?.forEach { it.cancel() }
527540
}
528541

529-
/**
530-
* Cancels all children of the [Job] in this context with an optional cancellation [cause],
531-
* without touching the the state of this job itself.
532-
* It does not do anything if there is no job in the context or it has no children.
533-
*
534-
* **Note: This is an experimental api.** Cancellation of a job with exception may change its semantics in the future.
535-
*/
536-
@ExperimentalCoroutinesApi
542+
@ObsoleteCoroutinesApi
543+
@Deprecated(level = DeprecationLevel.WARNING, message = "Use cancelChildren() without cause", replaceWith = ReplaceWith("cancelChildren()"))
537544
public fun CoroutineContext.cancelChildren(cause: Throwable? = null) {
538545
this[Job]?.children?.forEach { it.cancel(cause) }
539546
}

common/kotlinx-coroutines-core-common/src/JobSupport.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,8 +559,9 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
559559
internal open val onCancelComplete: Boolean get() = false
560560

561561
// external cancel without cause, never invoked implicitly from internal machinery
562-
public override fun cancel(): Boolean =
562+
public override fun cancel(): Unit {
563563
cancel(null) // must delegate here, because some classes override cancel(x)
564+
}
564565

565566
// external cancel with (optional) cause, never invoked implicitly from internal machinery
566567
public override fun cancel(cause: Throwable?): Boolean =

common/kotlinx-coroutines-core-common/src/NonCancellable.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,13 @@ public object NonCancellable : AbstractCoroutineContextElement(Job), Job {
8888
NonDisposableHandle
8989

9090
/**
91-
* Always returns `false`.
91+
* Does nothing.
9292
* @suppress **This an internal API and should not be used from general code.**
9393
*/
9494
@InternalCoroutinesApi
95-
override fun cancel(): Boolean = false
95+
@Suppress("RETURN_TYPE_MISMATCH_ON_OVERRIDE")
96+
override fun cancel(): Unit {
97+
}
9698

9799
/**
98100
* Always returns `false`.

common/kotlinx-coroutines-core-common/src/channels/AbstractChannel.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,9 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
657657
return if (result === POLL_FAILED) null else receiveOrNullResult(result)
658658
}
659659

660-
override fun cancel(): Boolean = cancel(null)
660+
override fun cancel(): Unit {
661+
cancel(null)
662+
}
661663

662664
override fun cancel(cause: Throwable?): Boolean =
663665
close(cause).also {

common/kotlinx-coroutines-core-common/src/channels/Channel.kt

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
package kotlinx.coroutines.channels
88

99
import kotlinx.coroutines.*
10-
import kotlinx.coroutines.channels.Channel.Factory.RENDEZVOUS
1110
import kotlinx.coroutines.channels.Channel.Factory.CONFLATED
11+
import kotlinx.coroutines.channels.Channel.Factory.RENDEZVOUS
1212
import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
1313
import kotlinx.coroutines.selects.*
14+
import kotlin.jvm.*
1415

1516
/**
1617
* Sender's interface to [Channel].
@@ -243,33 +244,28 @@ public interface ReceiveChannel<out E> {
243244
/**
244245
* Cancels reception of remaining elements from this channel. This function closes the channel
245246
* and removes all buffered sent elements from it.
246-
* This function returns `true` if the channel was not closed previously, or `false` otherwise.
247247
*
248248
* Immediately after invocation of this function [isClosedForReceive] and
249249
* [isClosedForSend][SendChannel.isClosedForSend]
250250
* on the side of [SendChannel] start returning `true`, so all attempts to send to this channel
251251
* afterwards will throw [ClosedSendChannelException], while attempts to receive will throw
252252
* [ClosedReceiveChannelException].
253253
*/
254-
public fun cancel(): Boolean
254+
public fun cancel(): Unit
255255

256256
/**
257-
* Cancels reception of remaining elements from this channel. This function closes the channel with
258-
* the specified cause (unless it was already closed) and removes all buffered sent elements from it.
259-
* This function returns `true` if the channel was not closed previously, or `false` otherwise.
260-
*
261-
* Immediately after invocation of this function [isClosedForReceive] and
262-
* [isClosedForSend][SendChannel.isClosedForSend]
263-
* on the side of [SendChannel] start returning `true`, so all attempts to send to this channel
264-
* afterwards will throw [ClosedSendChannelException], while attempts to receive will throw
265-
* [ClosedReceiveChannelException] if it was cancelled without a cause.
266-
* A channel that was cancelled with non-null [cause] is called a _failed_ channel. Attempts to send or
267-
* receive on a failed channel throw the specified [cause] exception.
268-
*
269-
* **Note: This is an experimental api.** Semantics of _cancelling_ a channel with exception may
270-
* change in the future or this feature may be completely removed.
257+
* @suppress
271258
*/
272-
@ExperimentalCoroutinesApi
259+
@Suppress("INAPPLICABLE_JVM_NAME")
260+
@Deprecated(level = DeprecationLevel.HIDDEN, message = "Left here for binary compatibility")
261+
@JvmName("cancel")
262+
public fun cancel0(): Boolean = cancel(null)
263+
264+
/**
265+
* @suppress
266+
*/
267+
@ObsoleteCoroutinesApi
268+
@Deprecated(level = DeprecationLevel.WARNING, message = "Use cancel without cause", replaceWith = ReplaceWith("cancel()"))
273269
public fun cancel(cause: Throwable? = null): Boolean
274270
}
275271

common/kotlinx-coroutines-core-common/src/channels/ChannelCoroutine.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ internal open class ChannelCoroutine<E>(
1616

1717
val channel: Channel<E> get() = this
1818

19-
override fun cancel() = cancel(null)
19+
override fun cancel(): Unit {
20+
cancel(null)
21+
}
22+
23+
override fun cancel0(): Boolean = cancel(null)
2024

2125
override fun cancel(cause: Throwable?): Boolean {
2226
val wasCancelled = _channel.cancel(cause)

common/kotlinx-coroutines-core-common/test/AsyncLazyTest.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,8 @@ class AsyncLazyTest : TestBase() {
150150
}
151151
expect(2)
152152
assertTrue(!d.isActive && !d.isCompleted)
153-
assertTrue(d.cancel())
153+
d.cancel()
154154
assertTrue(!d.isActive && d.isCompleted && d.isCancelled)
155-
assertTrue(!d.cancel())
156155
assertTrue(!d.start())
157156
finish(3)
158157
assertEquals(d.await(), 42) // await shall throw CancellationException
@@ -178,9 +177,8 @@ class AsyncLazyTest : TestBase() {
178177
yield() // yield to d
179178
expect(5)
180179
assertTrue(d.isActive && !d.isCompleted && !d.isCancelled)
181-
assertTrue(d.cancel())
180+
d.cancel()
182181
assertTrue(!d.isActive && d.isCancelled) // cancelling !
183-
assertTrue(d.cancel())
184182
assertTrue(!d.isActive && d.isCancelled) // still cancelling
185183
finish(6)
186184
assertEquals(d.await(), 42) // await shall throw CancellationException

0 commit comments

Comments
 (0)