@@ -690,11 +690,10 @@ internal open class JobSupport constructor(active: Boolean) : Job, SelectClause0
690690 }
691691 is Incomplete -> {
692692 // Not yet finishing -- try to make it failing
693- val list = tryPromoteToList(state) ? : return @loopOnState
694693 val causeException = causeExceptionCache ? : createCauseException(cause).also { causeExceptionCache = it }
695694 if (state.isActive) {
696695 // active state becomes failing
697- if (tryMakeFailing(state, list, causeException, cancel)) return true
696+ if (tryMakeFailing(state, causeException, cancel)) return true
698697 } else {
699698 // non active state starts completing
700699 when (tryMakeCompleting(state, createFailure(causeException, cancel), mode = MODE_ATOMIC_DEFAULT )) {
@@ -710,19 +709,26 @@ internal open class JobSupport constructor(active: Boolean) : Job, SelectClause0
710709 }
711710 }
712711
713- // Performs promotion of incomplete coroutine state to NodeList, returns null when need to retry
714- private fun tryPromoteToList (state : Incomplete ): NodeList ? = state.list ? : null .also {
712+ // Performs promotion of incomplete coroutine state to NodeList for the purpose of
713+ // converting coroutine state to Failing, returns null when need to retry
714+ private fun getOrPromoteFailingList (state : Incomplete ): NodeList ? = state.list ? :
715715 when (state) {
716- is Empty -> promoteEmptyToNodeList(state)
717- is JobNode <* > -> promoteSingleToNodeList(state)
716+ is Empty -> NodeList () // we can allocate new empty list that'll get integrated into Failing state
717+ is JobNode <* > -> {
718+ // SINGLE/SINGLE+ must be promoted to NodeList first, because otherwise we cannot
719+ // correctly capture a reference to it
720+ promoteSingleToNodeList(state)
721+ null // retry
722+ }
718723 else -> error(" State should have list: $state " )
719724 }
720- }
721725
722726 // try make new failing state on the condition that we're still in the expected state
723- private fun tryMakeFailing (state : Incomplete , list : NodeList , rootCause : Throwable , cancel : Boolean ): Boolean {
727+ private fun tryMakeFailing (state : Incomplete , rootCause : Throwable , cancel : Boolean ): Boolean {
724728 check(state !is Finishing ) // only for non-finishing states
725729 check(state.isActive) // only for active states
730+ // get state's list or else promote to list to correctly operate on child lists
731+ val list = getOrPromoteFailingList(state) ? : return false
726732 // Create failing state (with rootCause!)
727733 val failing = Finishing (list, cancel, false , rootCause)
728734 if (! _state .compareAndSet(state, failing)) return false
@@ -782,7 +788,7 @@ internal open class JobSupport constructor(active: Boolean) : Job, SelectClause0
782788 return COMPLETING_COMPLETED
783789 }
784790 // get state's list or else promote to list to correctly operate on child lists
785- val list = tryPromoteToList (state) ? : return COMPLETING_RETRY
791+ val list = getOrPromoteFailingList (state) ? : return COMPLETING_RETRY
786792 // promote to Finishing state if we are not in it yet
787793 // This promotion has to be atomic w.r.t to state change, so that a coroutine that is not active yet
788794 // atomically transition to finishing & completing state
0 commit comments