Introduce RequiresOptIn and OptIn annotations

RequiresOptIn should be used now instead of Experimental, OptIn instead
of UseExperimental. See https://github.com/Kotlin/KEEP/pull/201.

This change adds the new declarations only to the stdlib, and supports
them in the compiler. Because of the way compiler loads annotations, we
need to bootstrap it first before deprecating the old annotations and
updating tests.

 #KT-34647 Fixed
This commit is contained in:
Alexander Udalov
2019-12-13 21:11:48 +03:00
parent 33bc3db144
commit cdbabf224f
17 changed files with 119 additions and 39 deletions
@@ -147,22 +147,22 @@ public class DefaultErrorMessages {
MAP.put(ILLEGAL_KOTLIN_VERSION_STRING_VALUE, "Invalid @{0} annotation value (should be ''major.minor'' or ''major.minor.patch'')", TO_STRING); MAP.put(ILLEGAL_KOTLIN_VERSION_STRING_VALUE, "Invalid @{0} annotation value (should be ''major.minor'' or ''major.minor.patch'')", TO_STRING);
MAP.put(NEWER_VERSION_IN_SINCE_KOTLIN, "The version is greater than the specified API version {0}", STRING); MAP.put(NEWER_VERSION_IN_SINCE_KOTLIN, "The version is greater than the specified API version {0}", STRING);
MAP.put(EXPERIMENTAL_API_USAGE, "This declaration is experimental and its usage should be marked with ''@{0}'' or ''@UseExperimental({0}::class)''", TO_STRING); MAP.put(EXPERIMENTAL_API_USAGE, "This declaration is experimental and its usage should be marked with ''@{0}'' or ''@OptIn({0}::class)''", TO_STRING);
MAP.put(EXPERIMENTAL_API_USAGE_ERROR, "This declaration is experimental and its usage must be marked with ''@{0}'' or ''@UseExperimental({0}::class)''", TO_STRING); MAP.put(EXPERIMENTAL_API_USAGE_ERROR, "This declaration is experimental and its usage must be marked with ''@{0}'' or ''@OptIn({0}::class)''", TO_STRING);
MAP.put(EXPERIMENTAL_OVERRIDE, "This declaration overrides experimental member of supertype ''{1}'' and should be annotated with ''@{0}''", TO_STRING, NAME); MAP.put(EXPERIMENTAL_OVERRIDE, "This declaration overrides experimental member of supertype ''{1}'' and should be annotated with ''@{0}''", TO_STRING, NAME);
MAP.put(EXPERIMENTAL_OVERRIDE_ERROR, "This declaration overrides experimental member of supertype ''{1}'' and must be annotated with ''@{0}''", TO_STRING, NAME); MAP.put(EXPERIMENTAL_OVERRIDE_ERROR, "This declaration overrides experimental member of supertype ''{1}'' and must be annotated with ''@{0}''", TO_STRING, NAME);
MAP.put(EXPERIMENTAL_IS_NOT_ENABLED, "This class can only be used with the compiler argument '-Xuse-experimental=kotlin.Experimental'"); MAP.put(EXPERIMENTAL_IS_NOT_ENABLED, "This class can only be used with the compiler argument '-Xopt-in=kotlin.RequiresOptIn'");
MAP.put(EXPERIMENTAL_CAN_ONLY_BE_USED_AS_ANNOTATION, "This class can only be used as an annotation"); MAP.put(EXPERIMENTAL_CAN_ONLY_BE_USED_AS_ANNOTATION, "This class can only be used as an annotation");
MAP.put(EXPERIMENTAL_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_USE_EXPERIMENTAL, "This class can only be used as an annotation or as an argument to @UseExperimental"); MAP.put(EXPERIMENTAL_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_USE_EXPERIMENTAL, "This class can only be used as an annotation or as an argument to @OptIn");
MAP.put(USE_EXPERIMENTAL_WITHOUT_ARGUMENTS, "@UseExperimental without any arguments has no effect"); MAP.put(USE_EXPERIMENTAL_WITHOUT_ARGUMENTS, "@OptIn without any arguments has no effect");
MAP.put(USE_EXPERIMENTAL_ARGUMENT_IS_NOT_MARKER, "Annotation ''{0}'' is not an experimental API marker, therefore its usage in @UseExperimental is ignored", TO_STRING); MAP.put(USE_EXPERIMENTAL_ARGUMENT_IS_NOT_MARKER, "Annotation ''{0}'' is not an experimental API marker, therefore its usage in @OptIn is ignored", TO_STRING);
MAP.put(EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET, "Experimental annotation cannot be used on the following code elements: {0}. Please remove these targets", STRING); MAP.put(EXPERIMENTAL_ANNOTATION_WITH_WRONG_TARGET, "Experimental annotation cannot be used on the following code elements: {0}. Please remove these targets", STRING);
MAP.put(EXPERIMENTAL_UNSIGNED_LITERALS, "Unsigned literals are experimental and their usages should be marked with ''@{0}'' or ''@UseExperimental({0}::class)''", TO_STRING); MAP.put(EXPERIMENTAL_UNSIGNED_LITERALS, "Unsigned literals are experimental and their usages should be marked with ''@{0}'' or ''@OptIn({0}::class)''", TO_STRING);
MAP.put(EXPERIMENTAL_UNSIGNED_LITERALS_ERROR, "Unsigned literals are experimental and their usages must be marked with ''@{0}'' or ''@UseExperimental({0}::class)''", TO_STRING); MAP.put(EXPERIMENTAL_UNSIGNED_LITERALS_ERROR, "Unsigned literals are experimental and their usages must be marked with ''@{0}'' or ''@OptIn({0}::class)''", TO_STRING);
MAP.put(NON_PARENTHESIZED_ANNOTATIONS_ON_FUNCTIONAL_TYPES, "Non-parenthesized annotations on function types without receiver aren't yet supported (see KT-31734 for details)"); MAP.put(NON_PARENTHESIZED_ANNOTATIONS_ON_FUNCTIONAL_TYPES, "Non-parenthesized annotations on function types without receiver aren't yet supported (see KT-31734 for details)");
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.resolve.constants.ArrayValue
import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.KClassValue import org.jetbrains.kotlin.resolve.constants.KClassValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class ExperimentalMarkerDeclarationAnnotationChecker(private val module: ModuleDescriptor) : AdditionalAnnotationChecker { class ExperimentalMarkerDeclarationAnnotationChecker(private val module: ModuleDescriptor) : AdditionalAnnotationChecker {
private val WRONG_TARGETS_FOR_MARKER = setOf(KotlinTarget.EXPRESSION, KotlinTarget.FILE) private val WRONG_TARGETS_FOR_MARKER = setOf(KotlinTarget.EXPRESSION, KotlinTarget.FILE)
@@ -29,12 +30,13 @@ class ExperimentalMarkerDeclarationAnnotationChecker(private val module: ModuleD
for (entry in entries) { for (entry in entries) {
val annotation = trace.bindingContext.get(BindingContext.ANNOTATION, entry) val annotation = trace.bindingContext.get(BindingContext.ANNOTATION, entry)
when (annotation?.fqName) { when (annotation?.fqName) {
ExperimentalUsageChecker.USE_EXPERIMENTAL_FQ_NAME -> { in ExperimentalUsageChecker.USE_EXPERIMENTAL_FQ_NAMES -> {
val annotationClasses = val annotationClasses =
(annotation.allValueArguments[ExperimentalUsageChecker.USE_EXPERIMENTAL_ANNOTATION_CLASS] as? ArrayValue)?.value.orEmpty() annotation!!.allValueArguments[ExperimentalUsageChecker.USE_EXPERIMENTAL_ANNOTATION_CLASS]
.safeAs<ArrayValue>()?.value.orEmpty()
checkUseExperimentalUsage(annotationClasses, trace, entry) checkUseExperimentalUsage(annotationClasses, trace, entry)
} }
ExperimentalUsageChecker.EXPERIMENTAL_FQ_NAME -> { in ExperimentalUsageChecker.EXPERIMENTAL_FQ_NAMES -> {
isAnnotatedWithExperimental = true isAnnotatedWithExperimental = true
} }
} }
@@ -43,7 +43,6 @@ import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.deprecation.DeprecationSettings import org.jetbrains.kotlin.resolve.deprecation.DeprecationSettings
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.utils.SmartSet import org.jetbrains.kotlin.utils.SmartSet
@@ -72,8 +71,14 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
} }
companion object { companion object {
val EXPERIMENTAL_FQ_NAME = FqName("kotlin.Experimental") val OLD_EXPERIMENTAL_FQ_NAME = FqName("kotlin.Experimental")
val USE_EXPERIMENTAL_FQ_NAME = FqName("kotlin.UseExperimental") val OLD_USE_EXPERIMENTAL_FQ_NAME = FqName("kotlin.UseExperimental")
val REQUIRES_OPT_IN_FQ_NAME = FqName("kotlin.RequiresOptIn")
val OPT_IN_FQ_NAME = FqName("kotlin.OptIn")
val EXPERIMENTAL_FQ_NAMES = setOf(OLD_EXPERIMENTAL_FQ_NAME, REQUIRES_OPT_IN_FQ_NAME)
val USE_EXPERIMENTAL_FQ_NAMES = setOf(OLD_USE_EXPERIMENTAL_FQ_NAME, OPT_IN_FQ_NAME)
internal val WAS_EXPERIMENTAL_FQ_NAME = FqName("kotlin.WasExperimental") internal val WAS_EXPERIMENTAL_FQ_NAME = FqName("kotlin.WasExperimental")
internal val USE_EXPERIMENTAL_ANNOTATION_CLASS = Name.identifier("markerClass") internal val USE_EXPERIMENTAL_ANNOTATION_CLASS = Name.identifier("markerClass")
internal val WAS_EXPERIMENTAL_ANNOTATION_CLASS = Name.identifier("markerClass") internal val WAS_EXPERIMENTAL_ANNOTATION_CLASS = Name.identifier("markerClass")
@@ -82,9 +87,6 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
private val WARNING_LEVEL = Name.identifier("WARNING") private val WARNING_LEVEL = Name.identifier("WARNING")
private val ERROR_LEVEL = Name.identifier("ERROR") private val ERROR_LEVEL = Name.identifier("ERROR")
private val EXPERIMENTAL_SHORT_NAME = EXPERIMENTAL_FQ_NAME.shortName()
private val USE_EXPERIMENTAL_SHORT_NAME = USE_EXPERIMENTAL_FQ_NAME.shortName()
private val EXPERIMENTAL_API_DIAGNOSTICS = ExperimentalityDiagnostics( private val EXPERIMENTAL_API_DIAGNOSTICS = ExperimentalityDiagnostics(
Errors.EXPERIMENTAL_API_USAGE, Errors.EXPERIMENTAL_API_USAGE_ERROR Errors.EXPERIMENTAL_API_USAGE, Errors.EXPERIMENTAL_API_USAGE_ERROR
) )
@@ -146,7 +148,10 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
} }
internal fun ClassDescriptor.loadExperimentalityForMarkerAnnotation(): Experimentality? { internal fun ClassDescriptor.loadExperimentalityForMarkerAnnotation(): Experimentality? {
val experimental = annotations.findAnnotation(EXPERIMENTAL_FQ_NAME) ?: return null val experimental =
annotations.findAnnotation(REQUIRES_OPT_IN_FQ_NAME)
?: annotations.findAnnotation(OLD_EXPERIMENTAL_FQ_NAME)
?: return null
val severity = when ((experimental.allValueArguments[LEVEL] as? EnumValue)?.enumEntryName) { val severity = when ((experimental.allValueArguments[LEVEL] as? EnumValue)?.enumEntryName) {
WARNING_LEVEL -> Experimentality.Severity.WARNING WARNING_LEVEL -> Experimentality.Severity.WARNING
@@ -187,7 +192,7 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
private fun PsiElement.isElementAnnotatedWithUseExperimentalOf(annotationFqName: FqName, bindingContext: BindingContext): Boolean { private fun PsiElement.isElementAnnotatedWithUseExperimentalOf(annotationFqName: FqName, bindingContext: BindingContext): Boolean {
return this is KtAnnotated && annotationEntries.any { entry -> return this is KtAnnotated && annotationEntries.any { entry ->
val descriptor = bindingContext.get(BindingContext.ANNOTATION, entry) val descriptor = bindingContext.get(BindingContext.ANNOTATION, entry)
if (descriptor?.fqName == USE_EXPERIMENTAL_FQ_NAME) { if (descriptor != null && descriptor.fqName in USE_EXPERIMENTAL_FQ_NAMES) {
val annotationClasses = descriptor.allValueArguments[USE_EXPERIMENTAL_ANNOTATION_CLASS] val annotationClasses = descriptor.allValueArguments[USE_EXPERIMENTAL_ANNOTATION_CLASS]
annotationClasses is ArrayValue && annotationClasses.value.any { annotationClass -> annotationClasses is ArrayValue && annotationClasses.value.any { annotationClass ->
annotationClass is KClassValue && annotationClass.value.let { value -> annotationClass is KClassValue && annotationClass.value.let { value ->
@@ -244,7 +249,7 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
val validExperimental = languageVersionSettings.getFlag(AnalysisFlags.experimental).filter(::checkAnnotation) val validExperimental = languageVersionSettings.getFlag(AnalysisFlags.experimental).filter(::checkAnnotation)
val validUseExperimental = languageVersionSettings.getFlag(AnalysisFlags.useExperimental).filter { fqName -> val validUseExperimental = languageVersionSettings.getFlag(AnalysisFlags.useExperimental).filter { fqName ->
fqName == EXPERIMENTAL_FQ_NAME.asString() || checkAnnotation(fqName) fqName == REQUIRES_OPT_IN_FQ_NAME.asString() || fqName == OLD_EXPERIMENTAL_FQ_NAME.asString() || checkAnnotation(fqName)
} }
for (fqName in validExperimental.intersect(validUseExperimental)) { for (fqName in validExperimental.intersect(validUseExperimental)) {
@@ -258,9 +263,10 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) { override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) {
val name = targetDescriptor.name val name = targetDescriptor.name
if (name == EXPERIMENTAL_SHORT_NAME || name == USE_EXPERIMENTAL_SHORT_NAME) { if (name == OLD_EXPERIMENTAL_FQ_NAME.shortName() || name == REQUIRES_OPT_IN_FQ_NAME.shortName() ||
val fqName = targetDescriptor.fqNameUnsafe name == OLD_USE_EXPERIMENTAL_FQ_NAME.shortName() || name == OPT_IN_FQ_NAME.shortName()) {
if (fqName == EXPERIMENTAL_FQ_NAME.toUnsafe() || fqName == USE_EXPERIMENTAL_FQ_NAME.toUnsafe()) { val fqName = targetDescriptor.fqNameSafe
if (fqName in EXPERIMENTAL_FQ_NAMES || fqName in USE_EXPERIMENTAL_FQ_NAMES) {
checkUsageOfKotlinExperimentalOrUseExperimental(element, context) checkUsageOfKotlinExperimentalOrUseExperimental(element, context)
return return
} }
@@ -288,7 +294,9 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
} }
private fun checkUsageOfKotlinExperimentalOrUseExperimental(element: PsiElement, context: CheckerContext) { private fun checkUsageOfKotlinExperimentalOrUseExperimental(element: PsiElement, context: CheckerContext) {
if (EXPERIMENTAL_FQ_NAME.asString() !in context.languageVersionSettings.getFlag(AnalysisFlags.useExperimental)) { val useExperimentalFqNames = context.languageVersionSettings.getFlag(AnalysisFlags.useExperimental)
if (REQUIRES_OPT_IN_FQ_NAME.asString() !in useExperimentalFqNames &&
OLD_EXPERIMENTAL_FQ_NAME.asString() !in useExperimentalFqNames) {
context.trace.report(Errors.EXPERIMENTAL_IS_NOT_ENABLED.on(element)) context.trace.report(Errors.EXPERIMENTAL_IS_NOT_ENABLED.on(element))
} }
@@ -317,7 +325,7 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
parent.parent.parent is KtValueArgumentList && parent.parent.parent is KtValueArgumentList &&
parent.parent.parent.parent.let { entry -> parent.parent.parent.parent.let { entry ->
entry is KtAnnotationEntry && bindingContext.get(BindingContext.ANNOTATION, entry)?.let { annotation -> entry is KtAnnotationEntry && bindingContext.get(BindingContext.ANNOTATION, entry)?.let { annotation ->
annotation.fqName == USE_EXPERIMENTAL_FQ_NAME || annotation.fqName == WAS_EXPERIMENTAL_FQ_NAME annotation.fqName in USE_EXPERIMENTAL_FQ_NAMES || annotation.fqName == WAS_EXPERIMENTAL_FQ_NAME
} == true } == true
} }
} }
@@ -210,7 +210,9 @@ private val OVERRIDE_RENDERER = withOptions {
typeNormalizer = IdeDescriptorRenderers.APPROXIMATE_FLEXIBLE_TYPES typeNormalizer = IdeDescriptorRenderers.APPROXIMATE_FLEXIBLE_TYPES
renderUnabbreviatedType = false renderUnabbreviatedType = false
annotationFilter = { annotationFilter = {
it.type.constructor.declarationDescriptor?.annotations?.hasAnnotation(ExperimentalUsageChecker.EXPERIMENTAL_FQ_NAME) ?: false val annotations = it.type.constructor.declarationDescriptor?.annotations
annotations != null && (annotations.hasAnnotation(ExperimentalUsageChecker.REQUIRES_OPT_IN_FQ_NAME) ||
annotations.hasAnnotation(ExperimentalUsageChecker.OLD_EXPERIMENTAL_FQ_NAME))
} }
presentableUnresolvedTypes = true presentableUnresolvedTypes = true
informativeErrorType = false informativeErrorType = false
@@ -71,7 +71,7 @@ object ExperimentalFixesFactory : KotlinIntentionActionsFactory() {
} }
result.add( result.add(
AddAnnotationFix( AddAnnotationFix(
containingDeclaration, ExperimentalUsageChecker.USE_EXPERIMENTAL_FQ_NAME, suffix, annotationFqName containingDeclaration, ExperimentalUsageChecker.OPT_IN_FQ_NAME, suffix, annotationFqName
) )
) )
} }
@@ -84,7 +84,7 @@ object ExperimentalFixesFactory : KotlinIntentionActionsFactory() {
} else { } else {
result.add( result.add(
AddAnnotationFix( AddAnnotationFix(
containingClassOrObject, ExperimentalUsageChecker.USE_EXPERIMENTAL_FQ_NAME, suffix, annotationFqName containingClassOrObject, ExperimentalUsageChecker.OPT_IN_FQ_NAME, suffix, annotationFqName
) )
) )
} }
@@ -100,4 +100,4 @@ object ExperimentalFixesFactory : KotlinIntentionActionsFactory() {
return result return result
} }
} }
@@ -56,7 +56,7 @@ class MakeModuleExperimentalFix(
val facet = KotlinFacet.get(module) ?: return true val facet = KotlinFacet.get(module) ?: return true
val facetSettings = facet.configuration.settings val facetSettings = facet.configuration.settings
val compilerSettings = facetSettings.compilerSettings ?: return true val compilerSettings = facetSettings.compilerSettings ?: return true
return if (annotationFqName != ExperimentalUsageChecker.EXPERIMENTAL_FQ_NAME) { return if (annotationFqName != ExperimentalUsageChecker.REQUIRES_OPT_IN_FQ_NAME) {
compilerArgument !in compilerSettings.additionalArgumentsAsList compilerArgument !in compilerSettings.additionalArgumentsAsList
} else { } else {
compilerSettings.additionalArgumentsAsList.none { compilerSettings.additionalArgumentsAsList.none {
@@ -69,7 +69,7 @@ class MakeModuleExperimentalFix(
override fun createAction(diagnostic: Diagnostic): IntentionAction? { override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val containingKtFile = diagnostic.psiElement.containingFile as? KtFile ?: return null val containingKtFile = diagnostic.psiElement.containingFile as? KtFile ?: return null
val module = containingKtFile.module ?: return null val module = containingKtFile.module ?: return null
return MakeModuleExperimentalFix(containingKtFile, module, ExperimentalUsageChecker.EXPERIMENTAL_FQ_NAME) return MakeModuleExperimentalFix(containingKtFile, module, ExperimentalUsageChecker.REQUIRES_OPT_IN_FQ_NAME)
} }
} }
} }
@@ -32,8 +32,11 @@ import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
import org.jetbrains.kotlin.idea.refactoring.fqName.fqName import org.jetbrains.kotlin.idea.refactoring.fqName.fqName
import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHint import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHint
import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass
import org.jetbrains.kotlin.idea.util.* import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.idea.util.hasInlineModifier
import org.jetbrains.kotlin.idea.util.isEffectivelyActual
import org.jetbrains.kotlin.idea.util.mustHaveValOrVar
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -259,7 +262,8 @@ private fun KtPsiFactory.repairSuperTypeList(
private val forbiddenAnnotationFqNames = setOf( private val forbiddenAnnotationFqNames = setOf(
ExpectedActualDeclarationChecker.OPTIONAL_EXPECTATION_FQ_NAME, ExpectedActualDeclarationChecker.OPTIONAL_EXPECTATION_FQ_NAME,
FqName("kotlin.ExperimentalMultiplatform"), FqName("kotlin.ExperimentalMultiplatform"),
ExperimentalUsageChecker.USE_EXPERIMENTAL_FQ_NAME ExperimentalUsageChecker.OPT_IN_FQ_NAME,
ExperimentalUsageChecker.OLD_USE_EXPERIMENTAL_FQ_NAME
) )
internal fun generateCallable( internal fun generateCallable(
@@ -443,4 +447,4 @@ fun TypeAccessibilityChecker.findAndApplyExistingClasses(elements: Collection<Kt
classes = newExistingClasses classes = newExistingClasses
} }
} }
@@ -171,6 +171,7 @@ public annotation class JsQualifier(val value: String)
* or with the `-Xuse-experimental=kotlin.js.ExperimentalJsExport` compiler option is given. * or with the `-Xuse-experimental=kotlin.js.ExperimentalJsExport` compiler option is given.
*/ */
@Experimental(level = Experimental.Level.WARNING) @Experimental(level = Experimental.Level.WARNING)
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@SinceKotlin("1.3") @SinceKotlin("1.3")
public annotation class ExperimentalJsExport public annotation class ExperimentalJsExport
@@ -15,6 +15,7 @@ import kotlin.annotation.AnnotationTarget.*
* or by using the compiler argument `-Xuse-experimental=kotlin.ExperimentalStdlibApi`. * or by using the compiler argument `-Xuse-experimental=kotlin.ExperimentalStdlibApi`.
*/ */
@Experimental(level = Experimental.Level.ERROR) @Experimental(level = Experimental.Level.ERROR)
@RequiresOptIn(level = RequiresOptIn.Level.ERROR)
@Retention(AnnotationRetention.BINARY) @Retention(AnnotationRetention.BINARY)
@Target( @Target(
CLASS, CLASS,
@@ -17,6 +17,7 @@ import kotlin.internal.RequireKotlinVersionKind
* or by using the compiler argument `-Xuse-experimental=kotlin.ExperimentalMultiplatform`. * or by using the compiler argument `-Xuse-experimental=kotlin.ExperimentalMultiplatform`.
*/ */
@Experimental @Experimental
@RequiresOptIn
@MustBeDocumented @MustBeDocumented
@Target( @Target(
CLASS, CLASS,
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlin
import kotlin.annotation.AnnotationRetention.BINARY
import kotlin.annotation.AnnotationRetention.SOURCE
import kotlin.annotation.AnnotationTarget.*
import kotlin.internal.RequireKotlin
import kotlin.internal.RequireKotlinVersionKind
import kotlin.reflect.KClass
/**
* Signals that the annotated annotation class is a marker of an API that requires an explicit opt-in.
*
* Call sites of any declaration annotated with that marker should opt-in to the API either by using [OptIn],
* or by being annotated with that marker themselves, effectively causing further propagation of the opt-in requirement.
*
* This class requires opt-in itself and can only be used with the compiler argument `-Xopt-in=kotlin.RequiresOptIn`.
*/
@Target(ANNOTATION_CLASS)
@Retention(BINARY)
@SinceKotlin("1.3")
@RequireKotlin("1.3.70", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)
public annotation class RequiresOptIn(val level: Level = Level.ERROR) {
/**
* Severity of the diagnostic that should be reported on usages which did not explicitly opted into
* the API either by using [OptIn] or by being annotated with the corresponding marker annotation.
*/
public enum class Level {
/** Specifies that a warning should be reported on incorrect usages of this API. */
WARNING,
/** Specifies that an error should be reported on incorrect usages of this API. */
ERROR,
}
}
/**
* Allows to use the API denoted by the given markers in the annotated file, declaration, or expression.
* If a declaration is annotated with [OptIn], its usages are **not** required to opt-in to that API.
*
* This class requires opt-in itself and can only be used with the compiler argument `-Xopt-in=kotlin.RequiresOptIn`.
*/
@Target(
CLASS, PROPERTY, LOCAL_VARIABLE, VALUE_PARAMETER, CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, EXPRESSION, FILE, TYPEALIAS
)
@Retention(SOURCE)
@SinceKotlin("1.3")
@RequireKotlin("1.3.70", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)
public annotation class OptIn(
vararg val markerClass: KClass<out Annotation>
)
@@ -19,6 +19,7 @@ import kotlin.internal.InlineOnly
@Retention(AnnotationRetention.BINARY) @Retention(AnnotationRetention.BINARY)
@SinceKotlin("1.3") @SinceKotlin("1.3")
@Experimental @Experimental
@RequiresOptIn
@MustBeDocumented @MustBeDocumented
public annotation class ExperimentalContracts public annotation class ExperimentalContracts
@@ -147,4 +148,4 @@ public enum class InvocationKind {
@InlineOnly @InlineOnly
@SinceKotlin("1.3") @SinceKotlin("1.3")
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
public inline fun contract(builder: ContractBuilder.() -> Unit) { } public inline fun contract(builder: ContractBuilder.() -> Unit) { }
@@ -13,6 +13,7 @@ package kotlin.experimental
* or by using the compiler argument `-Xuse-experimental=kotlin.experimental.ExperimentalTypeInference`. * or by using the compiler argument `-Xuse-experimental=kotlin.experimental.ExperimentalTypeInference`.
*/ */
@Experimental(level = Experimental.Level.ERROR) @Experimental(level = Experimental.Level.ERROR)
@RequiresOptIn(level = RequiresOptIn.Level.ERROR)
@MustBeDocumented @MustBeDocumented
@Retention(AnnotationRetention.BINARY) @Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.ANNOTATION_CLASS) @Target(AnnotationTarget.ANNOTATION_CLASS)
@@ -19,6 +19,7 @@ import kotlin.annotation.AnnotationTarget.*
* or by using the compiler argument `-Xuse-experimental=kotlin.time.ExperimentalTime`. * or by using the compiler argument `-Xuse-experimental=kotlin.time.ExperimentalTime`.
*/ */
@Experimental(level = Experimental.Level.ERROR) @Experimental(level = Experimental.Level.ERROR)
@RequiresOptIn(level = RequiresOptIn.Level.ERROR)
@MustBeDocumented @MustBeDocumented
@Retention(AnnotationRetention.BINARY) @Retention(AnnotationRetention.BINARY)
@Target( @Target(
@@ -35,4 +36,4 @@ import kotlin.annotation.AnnotationTarget.*
TYPEALIAS TYPEALIAS
) )
@SinceKotlin("1.3") @SinceKotlin("1.3")
public annotation class ExperimentalTime public annotation class ExperimentalTime
@@ -20,6 +20,7 @@ import kotlin.internal.RequireKotlinVersionKind
* It's recommended to propagate the experimental status to the API that depends on unsigned types by annotating it with this annotation. * It's recommended to propagate the experimental status to the API that depends on unsigned types by annotating it with this annotation.
*/ */
@Experimental(level = Experimental.Level.WARNING) @Experimental(level = Experimental.Level.WARNING)
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@MustBeDocumented @MustBeDocumented
@Target(CLASS, ANNOTATION_CLASS, PROPERTY, FIELD, LOCAL_VARIABLE, VALUE_PARAMETER, CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, TYPEALIAS) @Target(CLASS, ANNOTATION_CLASS, PROPERTY, FIELD, LOCAL_VARIABLE, VALUE_PARAMETER, CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, TYPEALIAS)
@Retention(AnnotationRetention.BINARY) @Retention(AnnotationRetention.BINARY)
@@ -6,5 +6,6 @@
package org.jetbrains.kotlin.gradle.targets.js.dsl package org.jetbrains.kotlin.gradle.targets.js.dsl
@Experimental(level = Experimental.Level.WARNING) @Experimental(level = Experimental.Level.WARNING)
// TODO: @RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(AnnotationTarget.FUNCTION) @Target(AnnotationTarget.FUNCTION)
annotation class ExperimentalDceDsl annotation class ExperimentalDceDsl
@@ -6,5 +6,6 @@
package org.jetbrains.kotlin.gradle.targets.js.dsl package org.jetbrains.kotlin.gradle.targets.js.dsl
@Experimental(level = Experimental.Level.WARNING) @Experimental(level = Experimental.Level.WARNING)
// TODO: @RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(AnnotationTarget.FUNCTION) @Target(AnnotationTarget.FUNCTION)
annotation class ExperimentalDistributionDsl annotation class ExperimentalDistributionDsl