Skip to content

Commit 61dd23c

Browse files
authored
Introduce SubclassOptInRequired to the codebase (#4115)
The initial stage of #3770 Marked: * Job, * Deferred and CompletableDeferred, * SharedFlow, StateFlow, * CancellableContinuation, * All of their `public` implementors.
1 parent 7fe0e0c commit 61dd23c

18 files changed

+73
-11
lines changed

kotlinx-coroutines-core/api/kotlinx-coroutines-core.api

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,9 @@ public final class kotlinx/coroutines/ExecutorsKt {
367367
public abstract interface annotation class kotlinx/coroutines/ExperimentalCoroutinesApi : java/lang/annotation/Annotation {
368368
}
369369

370+
public abstract interface annotation class kotlinx/coroutines/ExperimentalForInheritanceCoroutinesApi : java/lang/annotation/Annotation {
371+
}
372+
370373
public abstract interface annotation class kotlinx/coroutines/FlowPreview : java/lang/annotation/Annotation {
371374
}
372375

@@ -378,6 +381,9 @@ public final class kotlinx/coroutines/GlobalScope : kotlinx/coroutines/Coroutine
378381
public abstract interface annotation class kotlinx/coroutines/InternalCoroutinesApi : java/lang/annotation/Annotation {
379382
}
380383

384+
public abstract interface annotation class kotlinx/coroutines/InternalForInheritanceCoroutinesApi : java/lang/annotation/Annotation {
385+
}
386+
381387
public final class kotlinx/coroutines/InterruptibleKt {
382388
public static final fun runInterruptible (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
383389
public static synthetic fun runInterruptible$default (Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;

kotlinx-coroutines-core/api/kotlinx-coroutines-core.klib.api

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,12 +764,18 @@ open annotation class kotlinx.coroutines/DelicateCoroutinesApi : kotlin/Annotati
764764
open annotation class kotlinx.coroutines/ExperimentalCoroutinesApi : kotlin/Annotation { // kotlinx.coroutines/ExperimentalCoroutinesApi|null[0]
765765
constructor <init>() // kotlinx.coroutines/ExperimentalCoroutinesApi.<init>|<init>(){}[0]
766766
}
767+
open annotation class kotlinx.coroutines/ExperimentalForInheritanceCoroutinesApi : kotlin/Annotation { // kotlinx.coroutines/ExperimentalForInheritanceCoroutinesApi|null[0]
768+
constructor <init>() // kotlinx.coroutines/ExperimentalForInheritanceCoroutinesApi.<init>|<init>(){}[0]
769+
}
767770
open annotation class kotlinx.coroutines/FlowPreview : kotlin/Annotation { // kotlinx.coroutines/FlowPreview|null[0]
768771
constructor <init>() // kotlinx.coroutines/FlowPreview.<init>|<init>(){}[0]
769772
}
770773
open annotation class kotlinx.coroutines/InternalCoroutinesApi : kotlin/Annotation { // kotlinx.coroutines/InternalCoroutinesApi|null[0]
771774
constructor <init>() // kotlinx.coroutines/InternalCoroutinesApi.<init>|<init>(){}[0]
772775
}
776+
open annotation class kotlinx.coroutines/InternalForInheritanceCoroutinesApi : kotlin/Annotation { // kotlinx.coroutines/InternalForInheritanceCoroutinesApi|null[0]
777+
constructor <init>() // kotlinx.coroutines/InternalForInheritanceCoroutinesApi.<init>|<init>(){}[0]
778+
}
773779
open annotation class kotlinx.coroutines/ObsoleteCoroutinesApi : kotlin/Annotation { // kotlinx.coroutines/ObsoleteCoroutinesApi|null[0]
774780
constructor <init>() // kotlinx.coroutines/ObsoleteCoroutinesApi.<init>|<init>(){}[0]
775781
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import kotlin.coroutines.*
3030
*
3131
* @suppress **This an internal API and should not be used from general code.**
3232
*/
33+
@OptIn(InternalForInheritanceCoroutinesApi::class)
3334
@InternalCoroutinesApi
3435
public abstract class AbstractCoroutine<in T>(
3536
parentContext: CoroutineContext,

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,29 @@ public annotation class ObsoleteCoroutinesApi
9090
"so stable API could be provided instead"
9191
)
9292
public annotation class InternalCoroutinesApi
93+
94+
/**
95+
* Marks declarations that cannot be safely inherited from.
96+
*/
97+
@Target(AnnotationTarget.CLASS)
98+
@RequiresOptIn(
99+
level = RequiresOptIn.Level.WARNING, message =
100+
"Inheriting from this kotlinx.coroutines API is unstable. " +
101+
"Either new methods may be added in the future, which would break the inheritance, " +
102+
"or correctly inheriting from it requires fulfilling contracts that may change in the future."
103+
)
104+
public annotation class ExperimentalForInheritanceCoroutinesApi
105+
106+
/**
107+
* Marks declarations that cannot be safely inherited from.
108+
*/
109+
@Target(AnnotationTarget.CLASS)
110+
@RequiresOptIn(
111+
level = RequiresOptIn.Level.WARNING, message =
112+
"This is a kotlinx.coroutines API that is not intended to be inherited from, " +
113+
"as the library may handle predefined instances of this in a special manner. " +
114+
"This will be an error in a future release. " +
115+
"If you need to inherit from this, please describe your use case in " +
116+
"https://github.com/Kotlin/kotlinx.coroutines/issues, so that we can provide a stable API for inheritance. "
117+
)
118+
public annotation class InternalForInheritanceCoroutinesApi

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ public fun <T> CoroutineScope.async(
8888
return coroutine
8989
}
9090

91+
@OptIn(InternalForInheritanceCoroutinesApi::class)
9192
@Suppress("UNCHECKED_CAST")
9293
private open class DeferredCoroutine<T>(
9394
parentContext: CoroutineContext,

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ import kotlin.coroutines.intrinsics.*
4141
* +-----------+
4242
* ```
4343
*/
44+
@OptIn(ExperimentalSubclassOptIn::class)
45+
@SubclassOptInRequired(InternalForInheritanceCoroutinesApi::class)
4446
public interface CancellableContinuation<in T> : Continuation<T> {
4547
/**
4648
* Returns `true` when this continuation is active -- it has not completed or cancelled yet.

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ internal val RESUME_TOKEN = Symbol("RESUME_TOKEN")
2525
/**
2626
* @suppress **This is unstable API and it is subject to change.**
2727
*/
28+
@OptIn(InternalForInheritanceCoroutinesApi::class)
2829
@PublishedApi
2930
internal open class CancellableContinuationImpl<in T>(
3031
final override val delegate: Continuation<T>,

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@ import kotlinx.coroutines.selects.*
1515
*
1616
* All functions on this interface are **thread-safe** and can
1717
* be safely invoked from concurrent coroutines without external synchronization.
18-
*
19-
* **The `CompletableDeferred` interface is not stable for inheritance in 3rd party libraries**,
20-
* as new methods might be added to this interface in the future, but is stable for use.
2118
*/
19+
@OptIn(ExperimentalSubclassOptIn::class)
20+
@SubclassOptInRequired(markerClass = InternalForInheritanceCoroutinesApi::class)
2221
public interface CompletableDeferred<T> : Deferred<T> {
2322
/**
2423
* Completes this deferred value with a given [value]. The result is `true` if this deferred was
@@ -73,6 +72,7 @@ public fun <T> CompletableDeferred(value: T): CompletableDeferred<T> = Completab
7372
/**
7473
* Concrete implementation of [CompletableDeferred].
7574
*/
75+
@OptIn(InternalForInheritanceCoroutinesApi::class)
7676
@Suppress("UNCHECKED_CAST")
7777
private class CompletableDeferredImpl<T>(
7878
parent: Job?

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ package kotlinx.coroutines
1010
* **The `CompletableJob` interface is not stable for inheritance in 3rd party libraries**,
1111
* as new methods might be added to this interface in the future, but is stable for use.
1212
*/
13+
@OptIn(ExperimentalSubclassOptIn::class)
14+
@SubclassOptInRequired(markerClass = InternalForInheritanceCoroutinesApi::class)
1315
public interface CompletableJob : Job {
1416
/**
1517
* Completes this job. The result is `true` if this job was completed as a result of this invocation and

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ import kotlinx.coroutines.selects.*
2626
*
2727
* All functions on this interface and on all interfaces derived from it are **thread-safe** and can
2828
* be safely invoked from concurrent coroutines without external synchronization.
29-
*
30-
* **`Deferred` interface and all its derived interfaces are not stable for inheritance in 3rd party libraries**,
31-
* as new methods might be added to this interface in the future, but is stable for use.
3229
*/
30+
@OptIn(ExperimentalSubclassOptIn::class)
31+
@SubclassOptInRequired(markerClass = InternalForInheritanceCoroutinesApi::class)
3332
public interface Deferred<out T> : Job {
3433

3534
/**

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,9 @@ import kotlin.jvm.*
9999
*
100100
* All functions on this interface and on all interfaces derived from it are **thread-safe** and can
101101
* be safely invoked from concurrent coroutines without external synchronization.
102-
*
103-
* ### Not stable for inheritance
104-
*
105-
* **`Job` interface and all its derived interfaces are not stable for inheritance in 3rd party libraries**,
106-
* as new methods might be added to this interface in the future, but is stable for use.
107102
*/
103+
@OptIn(ExperimentalSubclassOptIn::class)
104+
@SubclassOptInRequired(markerClass = InternalForInheritanceCoroutinesApi::class)
108105
public interface Job : CoroutineContext.Element {
109106
/**
110107
* Key for [Job] instance in the coroutine context.
@@ -404,6 +401,7 @@ public fun interface DisposableHandle {
404401
*/
405402
@InternalCoroutinesApi
406403
@Deprecated(level = DeprecationLevel.ERROR, message = "This is internal API and may be removed in the future releases")
404+
@OptIn(InternalForInheritanceCoroutinesApi::class)
407405
public interface ChildJob : Job {
408406
/**
409407
* Parent is cancelling its child by invoking this method.
@@ -423,6 +421,7 @@ public interface ChildJob : Job {
423421
*/
424422
@InternalCoroutinesApi
425423
@Deprecated(level = DeprecationLevel.ERROR, message = "This is internal API and may be removed in the future releases")
424+
@OptIn(InternalForInheritanceCoroutinesApi::class)
426425
public interface ParentJob : Job {
427426
/**
428427
* Child job is using this method to learn its cancellation cause when the parent cancels it with [ChildJob.parentCancelled].

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import kotlin.jvm.*
1919
* @param active when `true` the job is created in _active_ state, when `false` in _new_ state. See [Job] for details.
2020
* @suppress **This is unstable API and it is subject to change.**
2121
*/
22+
@OptIn(InternalForInheritanceCoroutinesApi::class)
2223
@Deprecated(level = DeprecationLevel.ERROR, message = "This is internal API and may be removed in the future releases")
2324
public open class JobSupport constructor(active: Boolean) : Job, ChildJob, ParentJob {
2425
final override val key: CoroutineContext.Key<*> get() = Job
@@ -1419,6 +1420,7 @@ private class Empty(override val isActive: Boolean) : Incomplete {
14191420
override fun toString(): String = "Empty{${if (isActive) "Active" else "New" }}"
14201421
}
14211422

1423+
@OptIn(InternalForInheritanceCoroutinesApi::class)
14221424
@PublishedApi // for a custom job in the test module
14231425
internal open class JobImpl(parent: Job?) : JobSupport(true), CompletableJob {
14241426
init { initParentJob(parent) }

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import kotlin.coroutines.*
2121
* when the parent is cancelled, the whole parent-child relation between parent and child is severed.
2222
* The parent will not wait for the child's completion, nor will be cancelled when the child crashed.
2323
*/
24+
@OptIn(InternalForInheritanceCoroutinesApi::class)
2425
@Suppress("DeprecatedCallableAddReplaceWith")
2526
public object NonCancellable : AbstractCoroutineContextElement(Job), Job {
2627

kotlinx-coroutines-core/common/src/flow/SharedFlow.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ import kotlin.jvm.*
119119
* might be added to this interface in the future, but is stable for use.
120120
* Use the `MutableSharedFlow(replay, ...)` constructor function to create an implementation.
121121
*/
122+
@OptIn(ExperimentalSubclassOptIn::class)
123+
@SubclassOptInRequired(ExperimentalForInheritanceCoroutinesApi::class)
122124
public interface SharedFlow<out T> : Flow<T> {
123125
/**
124126
* A snapshot of the replay cache.
@@ -170,6 +172,8 @@ public interface SharedFlow<out T> : Flow<T> {
170172
* might be added to this interface in the future, but is stable for use.
171173
* Use the `MutableSharedFlow(...)` constructor function to create an implementation.
172174
*/
175+
@OptIn(ExperimentalSubclassOptIn::class)
176+
@SubclassOptInRequired(ExperimentalForInheritanceCoroutinesApi::class)
173177
public interface MutableSharedFlow<T> : SharedFlow<T>, FlowCollector<T> {
174178
/**
175179
* Emits a [value] to this shared flow, suspending on buffer overflow.
@@ -309,6 +313,7 @@ internal class SharedFlowSlot : AbstractSharedFlowSlot<SharedFlowImpl<*>>() {
309313
}
310314
}
311315

316+
@OptIn(ExperimentalForInheritanceCoroutinesApi::class)
312317
internal open class SharedFlowImpl<T>(
313318
private val replay: Int,
314319
private val bufferCapacity: Int,

kotlinx-coroutines-core/common/src/flow/StateFlow.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ import kotlin.coroutines.*
130130
* might be added to this interface in the future, but is stable for use.
131131
* Use the `MutableStateFlow(value)` constructor function to create an implementation.
132132
*/
133+
@OptIn(ExperimentalSubclassOptIn::class)
134+
@SubclassOptInRequired(ExperimentalForInheritanceCoroutinesApi::class)
133135
public interface StateFlow<out T> : SharedFlow<T> {
134136
/**
135137
* The current value of this state flow.
@@ -151,6 +153,8 @@ public interface StateFlow<out T> : SharedFlow<T> {
151153
* might be added to this interface in the future, but is stable for use.
152154
* Use the `MutableStateFlow()` constructor function to create an implementation.
153155
*/
156+
@OptIn(ExperimentalSubclassOptIn::class)
157+
@SubclassOptInRequired(ExperimentalForInheritanceCoroutinesApi::class)
154158
public interface MutableStateFlow<T> : StateFlow<T>, MutableSharedFlow<T> {
155159
/**
156160
* The current value of this state flow.
@@ -305,6 +309,7 @@ private class StateFlowSlot : AbstractSharedFlowSlot<StateFlowImpl<*>>() {
305309
}
306310
}
307311

312+
@OptIn(ExperimentalForInheritanceCoroutinesApi::class)
308313
private class StateFlowImpl<T>(
309314
initialState: Any // T | NULL
310315
) : AbstractSharedFlow<StateFlowSlot>(), MutableStateFlow<T>, CancellableFlow<T>, FusibleFlow<T> {

kotlinx-coroutines-core/common/src/flow/internal/AbstractSharedFlow.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package kotlinx.coroutines.flow.internal
22

3+
import kotlinx.coroutines.*
34
import kotlinx.coroutines.channels.*
45
import kotlinx.coroutines.flow.*
56
import kotlinx.coroutines.internal.*
@@ -113,6 +114,7 @@ internal abstract class AbstractSharedFlow<S : AbstractSharedFlowSlot<*>> : Sync
113114
*
114115
* To avoid that (especially in a more complex scenarios), we do not conflate subscription updates.
115116
*/
117+
@OptIn(ExperimentalForInheritanceCoroutinesApi::class)
116118
private class SubscriptionCountStateFlow(initialValue: Int) : StateFlow<Int>,
117119
SharedFlowImpl<Int>(1, Int.MAX_VALUE, BufferOverflow.DROP_OLDEST)
118120
{

kotlinx-coroutines-core/common/src/flow/operators/Share.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ public fun <T> MutableSharedFlow<T>.asSharedFlow(): SharedFlow<T> =
363363
public fun <T> MutableStateFlow<T>.asStateFlow(): StateFlow<T> =
364364
ReadonlyStateFlow(this, null)
365365

366+
@OptIn(ExperimentalForInheritanceCoroutinesApi::class)
366367
private class ReadonlySharedFlow<T>(
367368
flow: SharedFlow<T>,
368369
@Suppress("unused")
@@ -372,6 +373,7 @@ private class ReadonlySharedFlow<T>(
372373
fuseSharedFlow(context, capacity, onBufferOverflow)
373374
}
374375

376+
@OptIn(ExperimentalForInheritanceCoroutinesApi::class)
375377
private class ReadonlyStateFlow<T>(
376378
flow: StateFlow<T>,
377379
@Suppress("unused")
@@ -397,6 +399,7 @@ private class ReadonlyStateFlow<T>(
397399
public fun <T> SharedFlow<T>.onSubscription(action: suspend FlowCollector<T>.() -> Unit): SharedFlow<T> =
398400
SubscribedSharedFlow(this, action)
399401

402+
@OptIn(ExperimentalForInheritanceCoroutinesApi::class)
400403
private class SubscribedSharedFlow<T>(
401404
private val sharedFlow: SharedFlow<T>,
402405
private val action: suspend FlowCollector<T>.() -> Unit

kotlinx-coroutines-core/common/src/sync/Mutex.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ internal open class MutexImpl(locked: Boolean) : SemaphoreImpl(1, if (locked) 1
243243
return this
244244
}
245245

246+
@OptIn(InternalForInheritanceCoroutinesApi::class)
246247
private inner class CancellableContinuationWithOwner(
247248
@JvmField
248249
val cont: CancellableContinuationImpl<Unit>,

0 commit comments

Comments
 (0)