diff --git a/core/compiler.common/src/org/jetbrains/kotlin/resolve/checkers/OptInNames.kt b/core/compiler.common/src/org/jetbrains/kotlin/resolve/checkers/OptInNames.kt index 181fc4b8f1d..ed021a2c2c8 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/resolve/checkers/OptInNames.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/resolve/checkers/OptInNames.kt @@ -16,6 +16,8 @@ object OptInNames { val REQUIRES_OPT_IN_CLASS_ID = ClassId.topLevel(REQUIRES_OPT_IN_FQ_NAME) val OPT_IN_FQ_NAME = FqName("kotlin.OptIn") val OPT_IN_CLASS_ID = ClassId.topLevel(OPT_IN_FQ_NAME) + val SUBCLASS_OPT_IN_REQUIRED_FQ_NAME = FqName("kotlin.SubclassOptInRequired") + val SUBCLASS_OPT_IN_REQUIRED_CLASS_ID = ClassId.topLevel(SUBCLASS_OPT_IN_REQUIRED_FQ_NAME) val WAS_EXPERIMENTAL_FQ_NAME = FqName("kotlin.WasExperimental") val WAS_EXPERIMENTAL_CLASS_ID = ClassId.topLevel(WAS_EXPERIMENTAL_FQ_NAME) diff --git a/libraries/stdlib/api/js-v1/kotlin.kt b/libraries/stdlib/api/js-v1/kotlin.kt index 15868c89dc2..af0f95984ef 100644 --- a/libraries/stdlib/api/js-v1/kotlin.kt +++ b/libraries/stdlib/api/js-v1/kotlin.kt @@ -2755,6 +2755,15 @@ public final class String : kotlin.Comparable, kotlin.CharSequenc } } +@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS}) +@kotlin.annotation.Retention(value = AnnotationRetention.BINARY) +@kotlin.SinceKotlin(version = "1.8") +public final annotation class SubclassOptInRequired : kotlin.Annotation { + public constructor SubclassOptInRequired(markerClass: kotlin.reflect.KClass) + + public final val markerClass: kotlin.reflect.KClass { get; } +} + @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.PROPERTY, AnnotationTarget.FIELD, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.TYPE, AnnotationTarget.EXPRESSION, AnnotationTarget.FILE, AnnotationTarget.TYPEALIAS}) @kotlin.annotation.Retention(value = AnnotationRetention.SOURCE) public final annotation class Suppress : kotlin.Annotation { diff --git a/libraries/stdlib/api/js/kotlin.kt b/libraries/stdlib/api/js/kotlin.kt index d395b6368ec..ba47e9c3f0d 100644 --- a/libraries/stdlib/api/js/kotlin.kt +++ b/libraries/stdlib/api/js/kotlin.kt @@ -2389,6 +2389,15 @@ public final class String : kotlin.Comparable, kotlin.CharSequenc } } +@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS}) +@kotlin.annotation.Retention(value = AnnotationRetention.BINARY) +@kotlin.SinceKotlin(version = "1.8") +public final annotation class SubclassOptInRequired : kotlin.Annotation { + public constructor SubclassOptInRequired(markerClass: kotlin.reflect.KClass) + + public final val markerClass: kotlin.reflect.KClass { get; } +} + @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.PROPERTY, AnnotationTarget.FIELD, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.TYPE, AnnotationTarget.EXPRESSION, AnnotationTarget.FILE, AnnotationTarget.TYPEALIAS}) @kotlin.annotation.Retention(value = AnnotationRetention.SOURCE) public final annotation class Suppress : kotlin.Annotation { diff --git a/libraries/stdlib/src/kotlin/annotations/OptIn.kt b/libraries/stdlib/src/kotlin/annotations/OptIn.kt index d0fe1f2e3ef..a72b6e098d6 100644 --- a/libraries/stdlib/src/kotlin/annotations/OptIn.kt +++ b/libraries/stdlib/src/kotlin/annotations/OptIn.kt @@ -55,3 +55,27 @@ public annotation class RequiresOptIn( public annotation class OptIn( vararg val markerClass: KClass ) + +/** + * Forbids creation of subclasses/sub-interfaces from the annotated class/interface without explicit OptIn. + * + * This annotation is devoted to specific case when we want subclassing to be experimental. + * In this case we annotated the base class or interface with [SubclassOptInRequired]. + * Without an explicit opt-in we have a compilation error/warning on the subclass/sub-interface after that. + * + * There are three ways to negate this error/warning: + *
  1. Annotate subclass or interface with the marker annotation. In this case opt-in is propagated.
  2. + *
  3. Annotate subclass or interface with [OptIn]. In this case opt-in isn't propagated.
  4. + *
  5. Annotate subclass or interface with [SubclassOptInRequired]. In this case opt-in is propagated to subclasses/interfaces only.
  6. + *
+ * + * Note that [SubclassOptInRequired] does not negate an opt-in usage error itself. + * + * @property markerClass an opt-in marker to be required + */ +@Target(CLASS) +@Retention(BINARY) +@SinceKotlin("1.8") +public annotation class SubclassOptInRequired( + val markerClass: KClass +) diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt index 91e3088a38a..b56e6b8aa9a 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt @@ -235,6 +235,10 @@ public abstract interface annotation class kotlin/SinceKotlin : java/lang/annota public abstract fun version ()Ljava/lang/String; } +public abstract interface annotation class kotlin/SubclassOptInRequired : java/lang/annotation/Annotation { + public abstract fun markerClass ()Ljava/lang/Class; +} + public abstract interface annotation class kotlin/Suppress : java/lang/annotation/Annotation { public abstract fun names ()[Ljava/lang/String; }