@@ -24,17 +24,20 @@ internal class SelectBuilderImpl<R>(
24
24
25
25
@PublishedApi
26
26
internal fun getResult (): Any? {
27
- if (cont.isCompleted) return cont.getResult()
28
27
// In the current `select` design, the [select] and [selectUnbiased] functions
29
28
// do not wrap the operation in `suspendCoroutineUninterceptedOrReturn` and
30
29
// suspend explicitly via [doSelect] call, which returns the final result.
31
30
// However, [doSelect] is a suspend function, so it cannot be invoked directly.
31
+ // In addition, the `select` builder is eligible to throw an exception, which
32
+ // should be handled properly.
32
33
//
33
34
// As a solution, we:
34
- // 1) create a CancellableContinuationImpl with the provided unintercepted continuation as a delegate;
35
- // 2) wrap the [doSelect] call in an additional coroutine, which we launch in UNDISPATCHED mode;
36
- // 3) resume the created CancellableContinuationImpl after the [doSelect] invocation completes;
37
- // 4) use CancellableContinuationImpl.getResult() as a result of this function.
35
+ // 1) check whether the `select` building is already completed with exception, finishing immediately in this case;
36
+ // 2) create a CancellableContinuationImpl with the provided unintercepted continuation as a delegate;
37
+ // 3) wrap the [doSelect] call in an additional coroutine, which we launch in UNDISPATCHED mode;
38
+ // 4) resume the created CancellableContinuationImpl after the [doSelect] invocation completes;
39
+ // 5) use CancellableContinuationImpl.getResult() as a result of this function.
40
+ if (cont.isCompleted) return cont.getResult()
38
41
CoroutineScope (context).launch(start = CoroutineStart .UNDISPATCHED ) {
39
42
val result = try {
40
43
doSelect()
@@ -49,7 +52,7 @@ internal class SelectBuilderImpl<R>(
49
52
50
53
@PublishedApi
51
54
internal fun handleBuilderException (e : Throwable ) {
52
- cont.resumeWithException(e)
55
+ cont.resumeWithException(e) // will be thrown later via `cont.getResult()`
53
56
}
54
57
}
55
58
0 commit comments