Skip to content

Commit 9d79f33

Browse files
erokhinsqwwdfsad
authored andcommitted
Revert "Introduce EXACTLY_ONCE contracts to coroutineScope, supervisorScope, withContext, runBlocking, withTimeout and select (#2030)"
This reverts commit 397f10e
1 parent bbc99b9 commit 9d79f33

File tree

9 files changed

+32
-138
lines changed

9 files changed

+32
-138
lines changed

integration/kotlinx-coroutines-jdk8/src/time/Time.kt

+2-9
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
/*
22
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
4-
@file:OptIn(ExperimentalContracts::class)
5-
64
package kotlinx.coroutines.time
75

86
import kotlinx.coroutines.*
97
import kotlinx.coroutines.flow.*
108
import kotlinx.coroutines.selects.*
119
import java.time.*
1210
import java.time.temporal.*
13-
import kotlin.contracts.*
1411

1512
/**
1613
* "java.time" adapter method for [kotlinx.coroutines.delay].
@@ -38,12 +35,8 @@ public fun <R> SelectBuilder<R>.onTimeout(duration: Duration, block: suspend ()
3835
/**
3936
* "java.time" adapter method for [kotlinx.coroutines.withTimeout].
4037
*/
41-
public suspend fun <T> withTimeout(duration: Duration, block: suspend CoroutineScope.() -> T): T {
42-
contract {
43-
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
44-
}
45-
return kotlinx.coroutines.withTimeout(duration.coerceToMillis(), block)
46-
}
38+
public suspend fun <T> withTimeout(duration: Duration, block: suspend CoroutineScope.() -> T): T =
39+
kotlinx.coroutines.withTimeout(duration.coerceToMillis(), block)
4740

4841
/**
4942
* "java.time" adapter method for [kotlinx.coroutines.withTimeoutOrNull].

kotlinx-coroutines-core/common/src/Builders.common.kt

+21-28
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@
44

55
@file:JvmMultifileClass
66
@file:JvmName("BuildersKt")
7-
@file:OptIn(ExperimentalContracts::class)
87

98
package kotlinx.coroutines
109

1110
import kotlinx.atomicfu.*
1211
import kotlinx.coroutines.internal.*
1312
import kotlinx.coroutines.intrinsics.*
1413
import kotlinx.coroutines.selects.*
15-
import kotlin.contracts.*
1614
import kotlin.coroutines.*
1715
import kotlin.coroutines.intrinsics.*
1816
import kotlin.jvm.*
@@ -136,36 +134,31 @@ private class LazyDeferredCoroutine<T>(
136134
public suspend fun <T> withContext(
137135
context: CoroutineContext,
138136
block: suspend CoroutineScope.() -> T
139-
): T {
140-
contract {
141-
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
137+
): T = suspendCoroutineUninterceptedOrReturn sc@ { uCont ->
138+
// compute new context
139+
val oldContext = uCont.context
140+
val newContext = oldContext + context
141+
// always check for cancellation of new context
142+
newContext.checkCompletion()
143+
// FAST PATH #1 -- new context is the same as the old one
144+
if (newContext === oldContext) {
145+
val coroutine = ScopeCoroutine(newContext, uCont)
146+
return@sc coroutine.startUndispatchedOrReturn(coroutine, block)
142147
}
143-
return suspendCoroutineUninterceptedOrReturn sc@ { uCont ->
144-
// compute new context
145-
val oldContext = uCont.context
146-
val newContext = oldContext + context
147-
// always check for cancellation of new context
148-
newContext.checkCompletion()
149-
// FAST PATH #1 -- new context is the same as the old one
150-
if (newContext === oldContext) {
151-
val coroutine = ScopeCoroutine(newContext, uCont)
148+
// FAST PATH #2 -- the new dispatcher is the same as the old one (something else changed)
149+
// `equals` is used by design (see equals implementation is wrapper context like ExecutorCoroutineDispatcher)
150+
if (newContext[ContinuationInterceptor] == oldContext[ContinuationInterceptor]) {
151+
val coroutine = UndispatchedCoroutine(newContext, uCont)
152+
// There are changes in the context, so this thread needs to be updated
153+
withCoroutineContext(newContext, null) {
152154
return@sc coroutine.startUndispatchedOrReturn(coroutine, block)
153155
}
154-
// FAST PATH #2 -- the new dispatcher is the same as the old one (something else changed)
155-
// `equals` is used by design (see equals implementation is wrapper context like ExecutorCoroutineDispatcher)
156-
if (newContext[ContinuationInterceptor] == oldContext[ContinuationInterceptor]) {
157-
val coroutine = UndispatchedCoroutine(newContext, uCont)
158-
// There are changes in the context, so this thread needs to be updated
159-
withCoroutineContext(newContext, null) {
160-
return@sc coroutine.startUndispatchedOrReturn(coroutine, block)
161-
}
162-
}
163-
// SLOW PATH -- use new dispatcher
164-
val coroutine = DispatchedCoroutine(newContext, uCont)
165-
coroutine.initParentJob()
166-
block.startCoroutineCancellable(coroutine, coroutine)
167-
coroutine.getResult()
168156
}
157+
// SLOW PATH -- use new dispatcher
158+
val coroutine = DispatchedCoroutine(newContext, uCont)
159+
coroutine.initParentJob()
160+
block.startCoroutineCancellable(coroutine, coroutine)
161+
coroutine.getResult()
169162
}
170163

171164
/**

kotlinx-coroutines-core/common/src/CoroutineScope.kt

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
/*
22
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
4-
@file:OptIn(ExperimentalContracts::class)
54

65
package kotlinx.coroutines
76

87
import kotlinx.coroutines.internal.*
98
import kotlinx.coroutines.intrinsics.*
10-
import kotlin.contracts.*
119
import kotlin.coroutines.*
1210
import kotlin.coroutines.intrinsics.*
1311

@@ -185,15 +183,11 @@ public object GlobalScope : CoroutineScope {
185183
* or may throw a corresponding unhandled [Throwable] if there is any unhandled exception in this scope
186184
* (for example, from a crashed coroutine that was started with [launch][CoroutineScope.launch] in this scope).
187185
*/
188-
public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R {
189-
contract {
190-
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
191-
}
192-
return suspendCoroutineUninterceptedOrReturn { uCont ->
186+
public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R =
187+
suspendCoroutineUninterceptedOrReturn { uCont ->
193188
val coroutine = ScopeCoroutine(uCont.context, uCont)
194189
coroutine.startUndispatchedOrReturn(coroutine, block)
195190
}
196-
}
197191

198192
/**
199193
* Creates a [CoroutineScope] that wraps the given coroutine [context].

kotlinx-coroutines-core/common/src/Supervisor.kt

+3-8
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
/*
22
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
4-
@file:OptIn(ExperimentalContracts::class)
4+
55
@file:Suppress("DEPRECATION_ERROR")
66

77
package kotlinx.coroutines
88

99
import kotlinx.coroutines.internal.*
1010
import kotlinx.coroutines.intrinsics.*
11-
import kotlin.contracts.*
1211
import kotlin.coroutines.*
1312
import kotlin.coroutines.intrinsics.*
1413
import kotlin.jvm.*
@@ -48,15 +47,11 @@ public fun SupervisorJob0(parent: Job? = null) : Job = SupervisorJob(parent)
4847
* A failure of the scope itself (exception thrown in the [block] or cancellation) fails the scope with all its children,
4948
* but does not cancel parent job.
5049
*/
51-
public suspend fun <R> supervisorScope(block: suspend CoroutineScope.() -> R): R {
52-
contract {
53-
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
54-
}
55-
return suspendCoroutineUninterceptedOrReturn { uCont ->
50+
public suspend fun <R> supervisorScope(block: suspend CoroutineScope.() -> R): R =
51+
suspendCoroutineUninterceptedOrReturn { uCont ->
5652
val coroutine = SupervisorCoroutine(uCont.context, uCont)
5753
coroutine.startUndispatchedOrReturn(coroutine, block)
5854
}
59-
}
6055

6156
private class SupervisorJobImpl(parent: Job?) : JobImpl(parent) {
6257
override fun childCancelled(cause: Throwable): Boolean = false

kotlinx-coroutines-core/common/src/Timeout.kt

+2-11
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
/*
22
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
4-
@file:OptIn(ExperimentalContracts::class)
54

65
package kotlinx.coroutines
76

87
import kotlinx.coroutines.internal.*
98
import kotlinx.coroutines.intrinsics.*
109
import kotlinx.coroutines.selects.*
11-
import kotlin.contracts.*
1210
import kotlin.coroutines.*
1311
import kotlin.coroutines.intrinsics.*
1412
import kotlin.jvm.*
@@ -29,9 +27,6 @@ import kotlin.time.*
2927
* @param timeMillis timeout time in milliseconds.
3028
*/
3129
public suspend fun <T> withTimeout(timeMillis: Long, block: suspend CoroutineScope.() -> T): T {
32-
contract {
33-
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
34-
}
3530
if (timeMillis <= 0L) throw TimeoutCancellationException("Timed out immediately")
3631
return suspendCoroutineUninterceptedOrReturn { uCont ->
3732
setupTimeout(TimeoutCoroutine(timeMillis, uCont), block)
@@ -51,12 +46,8 @@ public suspend fun <T> withTimeout(timeMillis: Long, block: suspend CoroutineSco
5146
* Implementation note: how the time is tracked exactly is an implementation detail of the context's [CoroutineDispatcher].
5247
*/
5348
@ExperimentalTime
54-
public suspend fun <T> withTimeout(timeout: Duration, block: suspend CoroutineScope.() -> T): T {
55-
contract {
56-
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
57-
}
58-
return withTimeout(timeout.toDelayMillis(), block)
59-
}
49+
public suspend fun <T> withTimeout(timeout: Duration, block: suspend CoroutineScope.() -> T): T =
50+
withTimeout(timeout.toDelayMillis(), block)
6051

6152
/**
6253
* Runs a given suspending block of code inside a coroutine with a specified [timeout][timeMillis] and returns

kotlinx-coroutines-core/common/src/selects/Select.kt

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
/*
22
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
4-
@file:OptIn(ExperimentalContracts::class)
54

65
package kotlinx.coroutines.selects
76

@@ -11,7 +10,6 @@ import kotlinx.coroutines.channels.*
1110
import kotlinx.coroutines.internal.*
1211
import kotlinx.coroutines.intrinsics.*
1312
import kotlinx.coroutines.sync.*
14-
import kotlin.contracts.*
1513
import kotlin.coroutines.*
1614
import kotlin.coroutines.intrinsics.*
1715
import kotlin.jvm.*
@@ -201,11 +199,8 @@ public interface SelectInstance<in R> {
201199
* Note that this function does not check for cancellation when it is not suspended.
202200
* Use [yield] or [CoroutineScope.isActive] to periodically check for cancellation in tight loops if needed.
203201
*/
204-
public suspend inline fun <R> select(crossinline builder: SelectBuilder<R>.() -> Unit): R {
205-
contract {
206-
callsInPlace(builder, InvocationKind.EXACTLY_ONCE)
207-
}
208-
return suspendCoroutineUninterceptedOrReturn { uCont ->
202+
public suspend inline fun <R> select(crossinline builder: SelectBuilder<R>.() -> Unit): R =
203+
suspendCoroutineUninterceptedOrReturn { uCont ->
209204
val scope = SelectBuilderImpl(uCont)
210205
try {
211206
builder(scope)
@@ -214,7 +209,6 @@ public suspend inline fun <R> select(crossinline builder: SelectBuilder<R>.() ->
214209
}
215210
scope.getResult()
216211
}
217-
}
218212

219213

220214
@SharedImmutable

kotlinx-coroutines-core/common/test/BuilderContractsTest.kt

-52
This file was deleted.

kotlinx-coroutines-core/jvm/src/Builders.kt

-5
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@
44

55
@file:JvmMultifileClass
66
@file:JvmName("BuildersKt")
7-
@file:OptIn(ExperimentalContracts::class)
87

98
package kotlinx.coroutines
109

1110
import java.util.concurrent.locks.*
12-
import kotlin.contracts.*
1311
import kotlin.coroutines.*
1412

1513
/**
@@ -36,9 +34,6 @@ import kotlin.coroutines.*
3634
*/
3735
@Throws(InterruptedException::class)
3836
public fun <T> runBlocking(context: CoroutineContext = EmptyCoroutineContext, block: suspend CoroutineScope.() -> T): T {
39-
contract {
40-
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
41-
}
4237
val currentThread = Thread.currentThread()
4338
val contextInterceptor = context[ContinuationInterceptor]
4439
val eventLoop: EventLoop?

kotlinx-coroutines-core/jvm/test/RunBlockingTest.kt

-9
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,4 @@ class RunBlockingTest : TestBase() {
162162

163163
handle.dispose()
164164
}
165-
166-
@Test
167-
fun testContract() {
168-
val rb: Int
169-
runBlocking {
170-
rb = 42
171-
}
172-
rb.hashCode() // unused
173-
}
174165
}

0 commit comments

Comments
 (0)