@@ -11,6 +11,7 @@ import kotlinx.coroutines.intrinsics.*
11
11
import kotlinx.coroutines.selects.*
12
12
import kotlin.coroutines.*
13
13
import kotlin.coroutines.intrinsics.*
14
+ import kotlin.js.*
14
15
import kotlin.jvm.*
15
16
16
17
/* *
@@ -127,7 +128,8 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
127
128
private val _state = atomic<Any ?>(if (active) EMPTY_ACTIVE else EMPTY_NEW )
128
129
129
130
@Volatile
130
- private var parentHandle: ChildHandle ? = null
131
+ @JvmField
132
+ internal var parentHandle: ChildHandle ? = null
131
133
132
134
// ------------ initialization ------------
133
135
@@ -639,12 +641,12 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
639
641
// determine root cancellation cause of this job (why is it cancelling its children?)
640
642
val state = this .state
641
643
val rootCause = when (state) {
642
- is Finishing -> state.rootCause as ? CancellationException ? : JobCancellationException ( " Parent job was cancelled " , state.rootCause, this )
643
- is CompletedExceptionally -> state.cause as ? CancellationException ? : JobCancellationException ( " Parent job was cancelled " , state.cause, this )
644
+ is Finishing -> state.rootCause
645
+ is CompletedExceptionally -> state.cause
644
646
is Incomplete -> error(" Cannot be cancelling child in this state: $state " )
645
647
else -> null // create exception with the below code on normal completion
646
648
}
647
- return rootCause ? : JobCancellationException (" Parent job is ${stateString(state)} " , rootCause, this )
649
+ return ( rootCause as ? CancellationException ) ? : JobCancellationException (" Parent job is ${stateString(state)} " , rootCause, this )
648
650
}
649
651
650
652
// cause is Throwable or ParentJob when cancelChild was invoked
@@ -915,13 +917,13 @@ public open class JobSupport constructor(active: Boolean) : Job, ChildJob, Paren
915
917
protected open val cancelsParent: Boolean get() = true
916
918
917
919
/* *
918
- * Returns `true` for jobs that handle their exceptions or integrate them
919
- * into the job's result via [onCompletionInternal]. The only instance of the [Job] that does not
920
- * handle its exceptions is [JobImpl] and its subclass [SupervisorJobImpl].
920
+ * Returns `true` for jobs that handle their exceptions or integrate them into the job's result via [onCompletionInternal].
921
+ * A valid implementation of this getter should recursively check parent as well before returning `false`.
921
922
*
923
+ * The only instance of the [Job] that does not handle its exceptions is [JobImpl] and its subclass [SupervisorJobImpl].
922
924
* @suppress **This is unstable API and it is subject to change.*
923
925
*/
924
- protected open val handlesException: Boolean get() = true
926
+ internal open val handlesException: Boolean get() = true
925
927
926
928
/* *
927
929
* Handles the final job [exception] that was not handled by the parent coroutine.
@@ -1222,10 +1224,29 @@ private class Empty(override val isActive: Boolean) : Incomplete {
1222
1224
internal open class JobImpl (parent : Job ? ) : JobSupport(true ), CompletableJob {
1223
1225
init { initParentJobInternal(parent) }
1224
1226
override val onCancelComplete get() = true
1225
- override val handlesException: Boolean get() = false
1227
+ /*
1228
+ * Check whether parent is able to handle exceptions as well.
1229
+ * With this check, an exception in that pattern will be handled once:
1230
+ * ```
1231
+ * launch {
1232
+ * val child = Job(coroutineContext[Job])
1233
+ * launch(child) { throw ... }
1234
+ * }
1235
+ * ```
1236
+ */
1237
+ override val handlesException: Boolean = handlesException()
1226
1238
override fun complete () = makeCompleting(Unit )
1227
1239
override fun completeExceptionally (exception : Throwable ): Boolean =
1228
1240
makeCompleting(CompletedExceptionally (exception))
1241
+
1242
+ @JsName(" handlesExceptionF" )
1243
+ private fun handlesException (): Boolean {
1244
+ var parentJob = (parentHandle as ? ChildHandleNode )?.job ? : return false
1245
+ while (true ) {
1246
+ if (parentJob.handlesException) return true
1247
+ parentJob = (parentJob.parentHandle as ? ChildHandleNode )?.job ? : return false
1248
+ }
1249
+ }
1229
1250
}
1230
1251
1231
1252
// -------- invokeOnCompletion nodes
0 commit comments