|
4 | 4 |
|
5 | 5 | @file:JvmMultifileClass
|
6 | 6 | @file:JvmName("BuildersKt")
|
7 |
| -@file:OptIn(ExperimentalContracts::class) |
8 | 7 |
|
9 | 8 | package kotlinx.coroutines
|
10 | 9 |
|
11 | 10 | import kotlinx.atomicfu.*
|
12 | 11 | import kotlinx.coroutines.internal.*
|
13 | 12 | import kotlinx.coroutines.intrinsics.*
|
14 | 13 | import kotlinx.coroutines.selects.*
|
15 |
| -import kotlin.contracts.* |
16 | 14 | import kotlin.coroutines.*
|
17 | 15 | import kotlin.coroutines.intrinsics.*
|
18 | 16 | import kotlin.jvm.*
|
@@ -137,36 +135,31 @@ private class LazyDeferredCoroutine<T>(
|
137 | 135 | public suspend fun <T> withContext(
|
138 | 136 | context: CoroutineContext,
|
139 | 137 | block: suspend CoroutineScope.() -> T
|
140 |
| -): T { |
141 |
| - contract { |
142 |
| - callsInPlace(block, InvocationKind.EXACTLY_ONCE) |
| 138 | +): T = suspendCoroutineUninterceptedOrReturn sc@ { uCont -> |
| 139 | + // compute new context |
| 140 | + val oldContext = uCont.context |
| 141 | + val newContext = oldContext + context |
| 142 | + // always check for cancellation of new context |
| 143 | + newContext.checkCompletion() |
| 144 | + // FAST PATH #1 -- new context is the same as the old one |
| 145 | + if (newContext === oldContext) { |
| 146 | + val coroutine = ScopeCoroutine(newContext, uCont) |
| 147 | + return@sc coroutine.startUndispatchedOrReturn(coroutine, block) |
143 | 148 | }
|
144 |
| - return suspendCoroutineUninterceptedOrReturn sc@ { uCont -> |
145 |
| - // compute new context |
146 |
| - val oldContext = uCont.context |
147 |
| - val newContext = oldContext + context |
148 |
| - // always check for cancellation of new context |
149 |
| - newContext.checkCompletion() |
150 |
| - // FAST PATH #1 -- new context is the same as the old one |
151 |
| - if (newContext === oldContext) { |
152 |
| - val coroutine = ScopeCoroutine(newContext, uCont) |
| 149 | + // FAST PATH #2 -- the new dispatcher is the same as the old one (something else changed) |
| 150 | + // `equals` is used by design (see equals implementation is wrapper context like ExecutorCoroutineDispatcher) |
| 151 | + if (newContext[ContinuationInterceptor] == oldContext[ContinuationInterceptor]) { |
| 152 | + val coroutine = UndispatchedCoroutine(newContext, uCont) |
| 153 | + // There are changes in the context, so this thread needs to be updated |
| 154 | + withCoroutineContext(newContext, null) { |
153 | 155 | return@sc coroutine.startUndispatchedOrReturn(coroutine, block)
|
154 | 156 | }
|
155 |
| - // FAST PATH #2 -- the new dispatcher is the same as the old one (something else changed) |
156 |
| - // `equals` is used by design (see equals implementation is wrapper context like ExecutorCoroutineDispatcher) |
157 |
| - if (newContext[ContinuationInterceptor] == oldContext[ContinuationInterceptor]) { |
158 |
| - val coroutine = UndispatchedCoroutine(newContext, uCont) |
159 |
| - // There are changes in the context, so this thread needs to be updated |
160 |
| - withCoroutineContext(newContext, null) { |
161 |
| - return@sc coroutine.startUndispatchedOrReturn(coroutine, block) |
162 |
| - } |
163 |
| - } |
164 |
| - // SLOW PATH -- use new dispatcher |
165 |
| - val coroutine = DispatchedCoroutine(newContext, uCont) |
166 |
| - coroutine.initParentJob() |
167 |
| - block.startCoroutineCancellable(coroutine, coroutine) |
168 |
| - coroutine.getResult() |
169 | 157 | }
|
| 158 | + // SLOW PATH -- use new dispatcher |
| 159 | + val coroutine = DispatchedCoroutine(newContext, uCont) |
| 160 | + coroutine.initParentJob() |
| 161 | + block.startCoroutineCancellable(coroutine, coroutine) |
| 162 | + coroutine.getResult() |
170 | 163 | }
|
171 | 164 |
|
172 | 165 | /**
|
|
0 commit comments