Skip to content

Commit de0eea9

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 4ea4078 commit de0eea9

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.*
@@ -137,36 +135,31 @@ private class LazyDeferredCoroutine<T>(
137135
public suspend fun <T> withContext(
138136
context: CoroutineContext,
139137
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)
143148
}
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) {
153155
return@sc coroutine.startUndispatchedOrReturn(coroutine, block)
154156
}
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()
169157
}
158+
// SLOW PATH -- use new dispatcher
159+
val coroutine = DispatchedCoroutine(newContext, uCont)
160+
coroutine.initParentJob()
161+
block.startCoroutineCancellable(coroutine, coroutine)
162+
coroutine.getResult()
170163
}
171164

172165
/**

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.*
@@ -36,9 +34,6 @@ import kotlin.time.*
3634
* @param timeMillis timeout time in milliseconds.
3735
*/
3836
public suspend fun <T> withTimeout(timeMillis: Long, block: suspend CoroutineScope.() -> T): T {
39-
contract {
40-
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
41-
}
4237
if (timeMillis <= 0L) throw TimeoutCancellationException("Timed out immediately")
4338
return suspendCoroutineUninterceptedOrReturn { uCont ->
4439
setupTimeout(TimeoutCoroutine(timeMillis, uCont), block)
@@ -65,12 +60,8 @@ public suspend fun <T> withTimeout(timeMillis: Long, block: suspend CoroutineSco
6560
* > Implementation note: how the time is tracked exactly is an implementation detail of the context's [CoroutineDispatcher].
6661
*/
6762
@ExperimentalTime
68-
public suspend fun <T> withTimeout(timeout: Duration, block: suspend CoroutineScope.() -> T): T {
69-
contract {
70-
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
71-
}
72-
return withTimeout(timeout.toDelayMillis(), block)
73-
}
63+
public suspend fun <T> withTimeout(timeout: Duration, block: suspend CoroutineScope.() -> T): T =
64+
withTimeout(timeout.toDelayMillis(), block)
7465

7566
/**
7667
* 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.*
@@ -195,11 +193,8 @@ public interface SelectInstance<in R> {
195193
* Note that this function does not check for cancellation when it is not suspended.
196194
* Use [yield] or [CoroutineScope.isActive] to periodically check for cancellation in tight loops if needed.
197195
*/
198-
public suspend inline fun <R> select(crossinline builder: SelectBuilder<R>.() -> Unit): R {
199-
contract {
200-
callsInPlace(builder, InvocationKind.EXACTLY_ONCE)
201-
}
202-
return suspendCoroutineUninterceptedOrReturn { uCont ->
196+
public suspend inline fun <R> select(crossinline builder: SelectBuilder<R>.() -> Unit): R =
197+
suspendCoroutineUninterceptedOrReturn { uCont ->
203198
val scope = SelectBuilderImpl(uCont)
204199
try {
205200
builder(scope)
@@ -208,7 +203,6 @@ public suspend inline fun <R> select(crossinline builder: SelectBuilder<R>.() ->
208203
}
209204
scope.getResult()
210205
}
211-
}
212206

213207

214208
@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)