Skip to content

Commit 9bb7d70

Browse files
author
jiaoxiaodong
committed
Rethrow AbortFlowException upon cancellation (Kotlin#4034)
collectWhile catches AbortFlowException even if the CoroutineScope is cancelled while waiting on child tasks, causing it to fail to respond to cancel().
1 parent 1fcffbf commit 9bb7d70

File tree

2 files changed

+22
-1
lines changed

2 files changed

+22
-1
lines changed

kotlinx-coroutines-core/common/src/flow/operators/Limit.kt

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package kotlinx.coroutines.flow
55

66
import kotlinx.coroutines.*
77
import kotlinx.coroutines.flow.internal.*
8+
import kotlin.coroutines.*
89
import kotlin.jvm.*
910
import kotlinx.coroutines.flow.flow as safeFlow
1011
import kotlinx.coroutines.flow.internal.unsafeFlow as flow
@@ -133,5 +134,8 @@ internal suspend inline fun <T> Flow<T>.collectWhile(crossinline predicate: susp
133134
collect(collector)
134135
} catch (e: AbortFlowException) {
135136
e.checkOwnership(collector)
137+
// If thrown in a CoroutineScope waiting on child tasks, this exception can override a later CancellationException
138+
// from cancel(). Rethrow if it does.
139+
if (!coroutineContext.isActive) { throw e }
136140
}
137141
}

kotlinx-coroutines-core/common/test/flow/terminal/FirstTest.kt

+18-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ package kotlinx.coroutines.flow
22

33
import kotlinx.coroutines.testing.*
44
import kotlinx.coroutines.*
5+
import kotlinx.coroutines.CoroutineStart.*
56
import kotlinx.coroutines.channels.*
67
import kotlinx.coroutines.flow.internal.*
78
import kotlin.test.*
9+
import kotlin.time.*
810

911
class FirstTest : TestBase() {
1012
@Test
@@ -173,4 +175,19 @@ class FirstTest : TestBase() {
173175

174176
assertFailsWith<CancellationException> { flow.first() }
175177
}
176-
}
178+
179+
@Test
180+
fun test() = runTest {
181+
val job = launch(start = UNDISPATCHED) {
182+
flow {
183+
coroutineScope {
184+
emitAll(produce(start = UNDISPATCHED) {
185+
channel.send(Unit)
186+
})
187+
}
188+
}.first()
189+
expectUnreached()
190+
}
191+
job.cancel()
192+
}
193+
}

0 commit comments

Comments
 (0)