@@ -195,25 +195,38 @@ public class FlowSubscription<T>(
195
195
*/
196
196
private val requested = atomic(0L )
197
197
private val producer = atomic<Continuation <Unit >? > (createInitialContinuation())
198
+ @Volatile
199
+ private var cancellationRequested = false
198
200
199
201
// This code wraps startCoroutineCancellable into continuation
200
202
private fun createInitialContinuation (): Continuation <Unit > = Continuation (coroutineContext) {
201
203
::flowProcessing.startCoroutineCancellable(this )
202
204
}
203
205
204
206
private suspend fun flowProcessing () {
205
- try {
207
+ val consumeSucceeded = try {
206
208
consumeFlow()
207
- subscriber.onComplete()
208
- } catch (e: Throwable ) {
209
- try {
210
- if (e is CancellationException ) {
211
- subscriber.onComplete()
212
- } else {
213
- subscriber.onError(e)
209
+ true
210
+ } catch (cause: Throwable ) {
211
+ if (cancellationRequested && cause == = getCancellationException()) {
212
+ return
213
+ } else {
214
+ // TODO: this branch gets entered even when `cause` looks identical to `getCancellationException()`.
215
+ // Is stack sanitization to blame?
216
+ try {
217
+ subscriber.onError(cause)
218
+ } catch (e: Throwable ) {
219
+ // Last ditch report
220
+ cause.addSuppressed(e)
221
+ handleCoroutineException(coroutineContext, cause)
214
222
}
223
+ }
224
+ false
225
+ }
226
+ if (consumeSucceeded) {
227
+ try {
228
+ subscriber.onComplete()
215
229
} catch (e: Throwable ) {
216
- // Last ditch report
217
230
handleCoroutineException(coroutineContext, e)
218
231
}
219
232
}
@@ -239,6 +252,7 @@ public class FlowSubscription<T>(
239
252
}
240
253
241
254
override fun cancel () {
255
+ cancellationRequested = true
242
256
cancel(null )
243
257
}
244
258
0 commit comments