From 77625831f7888f54b2cb9ca90a30b9d6b80da4d5 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 2 Jan 2018 16:46:07 +0100 Subject: [PATCH] Support -Xexperimental and -Xuse-experimental, validate their values #KT-22759 In Progress --- .../arguments/CommonCompilerArguments.kt | 18 +++++++++- .../arguments/parseCommandLineArguments.kt | 1 + .../messages/AnalyzerWithCompilerReport.kt | 10 +++++- .../jetbrains/kotlin/cli/js/K2JSCompiler.java | 4 ++- .../compiler/KotlinToJVMBytecodeCompiler.kt | 7 ++-- .../kotlin/cli/metadata/MetadataSerializer.kt | 2 +- .../checkers/ExperimentalUsageChecker.kt | 36 ++++++++++++++++++- compiler/testData/cli/js/jsExtraHelp.out | 2 ++ ...lAndUseExperimentalWithSameAnnotation.args | 8 +++++ ...talAndUseExperimentalWithSameAnnotation.kt | 4 +++ ...alAndUseExperimentalWithSameAnnotation.out | 3 ++ .../cli/jvm/experimentalIsNotAnnotation.args | 5 +++ .../cli/jvm/experimentalIsNotAnnotation.kt | 4 +++ .../cli/jvm/experimentalIsNotAnnotation.out | 3 ++ .../cli/jvm/experimentalIsNotMarker.args | 5 +++ .../cli/jvm/experimentalIsNotMarker.kt | 4 +++ .../cli/jvm/experimentalIsNotMarker.out | 3 ++ .../testData/cli/jvm/experimentalNested.args | 7 ++++ .../testData/cli/jvm/experimentalNested.kt | 9 +++++ .../testData/cli/jvm/experimentalNested.out | 2 ++ .../cli/jvm/experimentalRuntimeScope.args | 8 +++++ .../cli/jvm/experimentalRuntimeScope.kt | 7 ++++ .../cli/jvm/experimentalRuntimeScope.out | 3 ++ .../cli/jvm/experimentalUnresolved.args | 6 ++++ .../cli/jvm/experimentalUnresolved.kt | 1 + .../cli/jvm/experimentalUnresolved.out | 4 +++ compiler/testData/cli/jvm/extraHelp.out | 2 ++ .../kotlin/cli/CliTestGenerated.java | 36 +++++++++++++++++++ .../jetbrains/kotlin/config/AnalysisFlag.kt | 10 ++++++ 29 files changed, 204 insertions(+), 10 deletions(-) create mode 100644 compiler/testData/cli/jvm/experimentalAndUseExperimentalWithSameAnnotation.args create mode 100644 compiler/testData/cli/jvm/experimentalAndUseExperimentalWithSameAnnotation.kt create mode 100644 compiler/testData/cli/jvm/experimentalAndUseExperimentalWithSameAnnotation.out create mode 100644 compiler/testData/cli/jvm/experimentalIsNotAnnotation.args create mode 100644 compiler/testData/cli/jvm/experimentalIsNotAnnotation.kt create mode 100644 compiler/testData/cli/jvm/experimentalIsNotAnnotation.out create mode 100644 compiler/testData/cli/jvm/experimentalIsNotMarker.args create mode 100644 compiler/testData/cli/jvm/experimentalIsNotMarker.kt create mode 100644 compiler/testData/cli/jvm/experimentalIsNotMarker.out create mode 100644 compiler/testData/cli/jvm/experimentalNested.args create mode 100644 compiler/testData/cli/jvm/experimentalNested.kt create mode 100644 compiler/testData/cli/jvm/experimentalNested.out create mode 100644 compiler/testData/cli/jvm/experimentalRuntimeScope.args create mode 100644 compiler/testData/cli/jvm/experimentalRuntimeScope.kt create mode 100644 compiler/testData/cli/jvm/experimentalRuntimeScope.out create mode 100644 compiler/testData/cli/jvm/experimentalUnresolved.args create mode 100644 compiler/testData/cli/jvm/experimentalUnresolved.kt create mode 100644 compiler/testData/cli/jvm/experimentalUnresolved.out diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt index 9bc12bd2a40..f055312aefb 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt @@ -123,7 +123,7 @@ abstract class CommonCompilerArguments : CommonToolArguments() { value = "-Xlegacy-smart-cast-after-try", description = "Allow var smart casts despite assignment in try block" ) - var legacySmartCastAfterTry by FreezableVar(false) + var legacySmartCastAfterTry: Boolean by FreezableVar(false) @Argument( value = "-Xeffect-system", @@ -137,11 +137,27 @@ abstract class CommonCompilerArguments : CommonToolArguments() { ) var readDeserializedContracts: Boolean by FreezableVar(false) + @Argument( + value = "-Xexperimental", + valueDescription = "", + description = "Enable and propagate usages of experimental API for marker annotation with the given fully qualified name" + ) + var experimental: Array? by FreezableVar(null) + + @Argument( + value = "-Xuse-experimental", + valueDescription = "", + description = "Enable usages of COMPILATION-affecting experimental API for marker annotation with the given fully qualified name" + ) + var useExperimental: Array? by FreezableVar(null) + open fun configureAnalysisFlags(collector: MessageCollector): MutableMap, Any> { return HashMap, Any>().apply { put(AnalysisFlag.skipMetadataVersionCheck, skipMetadataVersionCheck) put(AnalysisFlag.multiPlatformDoNotCheckActual, noCheckActual) put(AnalysisFlag.allowKotlinPackage, allowKotlinPackage) + put(AnalysisFlag.experimental, experimental?.toList().orEmpty()) + put(AnalysisFlag.useExperimental, useExperimental?.toList().orEmpty()) } } diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/parseCommandLineArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/parseCommandLineArguments.kt index 69ebfbb88d8..693c7e0b5d1 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/parseCommandLineArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/parseCommandLineArguments.kt @@ -22,6 +22,7 @@ import kotlin.reflect.KMutableProperty1 import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.memberProperties +@Target(AnnotationTarget.PROPERTY) annotation class Argument( val value: String, val shortName: String = "", diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/AnalyzerWithCompilerReport.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/AnalyzerWithCompilerReport.kt index 9b096980f0f..c57adfa9617 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/AnalyzerWithCompilerReport.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/AnalyzerWithCompilerReport.kt @@ -23,6 +23,7 @@ import com.intellij.psi.util.PsiFormatUtil import org.jetbrains.kotlin.analyzer.AnalysisResult import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.* import org.jetbrains.kotlin.codegen.state.IncompatibleClassTrackerImpl +import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.diagnostics.* import org.jetbrains.kotlin.diagnostics.DiagnosticUtils.sortedDiagnostics import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages @@ -33,12 +34,16 @@ import org.jetbrains.kotlin.resolve.AnalyzingUtils import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import org.jetbrains.kotlin.resolve.jvm.JvmBindingContextSlices import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData -class AnalyzerWithCompilerReport(private val messageCollector: MessageCollector) { +class AnalyzerWithCompilerReport( + private val messageCollector: MessageCollector, + private val languageVersionSettings: LanguageVersionSettings +) { lateinit var analysisResult: AnalysisResult private fun reportIncompleteHierarchies() { @@ -94,6 +99,9 @@ class AnalyzerWithCompilerReport(private val messageCollector: MessageCollector) fun analyzeAndReport(files: Collection, analyze: () -> AnalysisResult) { analysisResult = analyze() + ExperimentalUsageChecker.checkCompilerArguments(analysisResult.moduleDescriptor, languageVersionSettings) { message -> + messageCollector.report(ERROR, message) + } reportSyntaxErrors(files) reportDiagnostics(analysisResult.bindingContext.diagnostics, messageCollector) reportIncompleteHierarchies() diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java index f61a830ea0d..5754f4a53ff 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java @@ -222,7 +222,9 @@ public class K2JSCompiler extends CLICompiler { return COMPILATION_ERROR; } - AnalyzerWithCompilerReport analyzerWithCompilerReport = new AnalyzerWithCompilerReport(messageCollector); + AnalyzerWithCompilerReport analyzerWithCompilerReport = new AnalyzerWithCompilerReport( + messageCollector, CommonConfigurationKeysKt.getLanguageVersionSettings(configuration) + ); analyzerWithCompilerReport.analyzeAndReport(sourcesFiles, () -> TopDownAnalyzerFacadeForJS.analyzeFiles(sourcesFiles, config)); if (analyzerWithCompilerReport.hasErrors()) { return COMPILATION_ERROR; diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt index aaca1ede458..632faebd1f1 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt @@ -43,10 +43,7 @@ import org.jetbrains.kotlin.cli.jvm.config.* import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationStateEventCallback -import org.jetbrains.kotlin.config.CommonConfigurationKeys -import org.jetbrains.kotlin.config.CompilerConfiguration -import org.jetbrains.kotlin.config.JVMConfigurationKeys -import org.jetbrains.kotlin.config.addKotlinSourceRoots +import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.idea.MainFunctionDetector import org.jetbrains.kotlin.javac.JavacWrapper @@ -364,7 +361,7 @@ object KotlinToJVMBytecodeCompiler { val collector = environment.messageCollector val analysisStart = PerformanceCounter.currentTime() - val analyzerWithCompilerReport = AnalyzerWithCompilerReport(collector) + val analyzerWithCompilerReport = AnalyzerWithCompilerReport(collector, environment.configuration.languageVersionSettings) analyzerWithCompilerReport.analyzeAndReport(sourceFiles) { val project = environment.project val moduleOutputs = environment.configuration.get(JVMConfigurationKeys.MODULES)?.mapNotNullTo(hashSetOf()) { module -> diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt index 6aad377fff2..ed9a0b5c4b5 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializer.kt @@ -62,7 +62,7 @@ open class MetadataSerializer(private val dependOnOldBuiltIns: Boolean) { return } - val analyzer = AnalyzerWithCompilerReport(messageCollector) + val analyzer = AnalyzerWithCompilerReport(messageCollector, configuration.languageVersionSettings) analyzer.analyzeAndReport(files) { CommonAnalyzerFacade.analyzeFiles(files, moduleName, dependOnOldBuiltIns, configuration.languageVersionSettings) { _, content -> environment.createPackagePartProvider(content.moduleContentScope) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt index 4ee98c25557..0be34758d80 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt @@ -17,9 +17,12 @@ package org.jetbrains.kotlin.resolve.checkers import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.config.AnalysisFlag +import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* @@ -55,7 +58,7 @@ object ExperimentalUsageChecker : CallChecker { val markerDescriptor: ClassDescriptor, val annotationFqName: FqName, val severity: Severity, - private val impact: List + val impact: List ) { val isCompilationOnly: Boolean get() = impact.all(Impact.COMPILATION::equals) @@ -222,6 +225,37 @@ object ExperimentalUsageChecker : CallChecker { } } + fun checkCompilerArguments(module: ModuleDescriptor, languageVersionSettings: LanguageVersionSettings, reportError: (String) -> Unit) { + fun checkAnnotation(fqName: String, allowNonCompilationImpact: Boolean): Boolean { + val descriptor = module.resolveClassByFqName(FqName(fqName), NoLookupLocation.FOR_NON_TRACKED_SCOPE) + val experimentality = descriptor?.loadExperimentalityForMarkerAnnotation() + val message = when { + descriptor == null -> + "Experimental API marker $fqName is unresolved. " + + "Please make sure it's present in the module dependencies" + experimentality == null -> + "Class $fqName is not an experimental API marker annotation" + !allowNonCompilationImpact && !experimentality.impact.all(Experimentality.Impact.COMPILATION::equals) -> + "Experimental API marker $fqName has impact other than COMPILATION, " + + "therefore it can't be used with -Xuse-experimental" + else -> return true + } + reportError(message) + return false + } + + val validExperimental = + languageVersionSettings.getFlag(AnalysisFlag.experimental) + .filter { checkAnnotation(it, allowNonCompilationImpact = true) } + val validUseExperimental = + languageVersionSettings.getFlag(AnalysisFlag.useExperimental) + .filter { checkAnnotation(it, allowNonCompilationImpact = false) } + + for (fqName in validExperimental.intersect(validUseExperimental)) { + reportError("'-Xuse-experimental=$fqName' has no effect because '-Xexperimental=$fqName' is used") + } + } + object ClassifierUsage : ClassifierUsageChecker { override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) { checkExperimental(targetDescriptor, element, context) diff --git a/compiler/testData/cli/js/jsExtraHelp.out b/compiler/testData/cli/js/jsExtraHelp.out index 183d77b75bb..1e64a902713 100644 --- a/compiler/testData/cli/js/jsExtraHelp.out +++ b/compiler/testData/cli/js/jsExtraHelp.out @@ -7,6 +7,7 @@ where advanced options include: -Xcoroutines={enable|warn|error} Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier -Xeffect-system Enable experimental language feature: effect system + -Xexperimental= Enable and propagate usages of experimental API for marker annotation with the given fully qualified name -Xintellij-plugin-root= Path to the kotlin-compiler.jar or directory where IntelliJ configuration files can be found -Xlegacy-smart-cast-after-try Allow var smart casts despite assignment in try block -Xmulti-platform Enable experimental language support for multi-platform projects @@ -18,6 +19,7 @@ where advanced options include: -Xrepeat= Repeat compilation (for performance analysis) -Xreport-output-files Report source to output files mapping -Xskip-metadata-version-check Load classes with bad metadata version anyway (incl. pre-release classes) + -Xuse-experimental= Enable usages of COMPILATION-affecting experimental API for marker annotation with the given fully qualified name Advanced options are non-standard and may be changed or removed without any notice. OK diff --git a/compiler/testData/cli/jvm/experimentalAndUseExperimentalWithSameAnnotation.args b/compiler/testData/cli/jvm/experimentalAndUseExperimentalWithSameAnnotation.args new file mode 100644 index 00000000000..09db7a95795 --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalAndUseExperimentalWithSameAnnotation.args @@ -0,0 +1,8 @@ +$TESTDATA_DIR$/experimentalAndUseExperimentalWithSameAnnotation.kt +-d +$TEMP_DIR$ +-Xskip-runtime-version-check +-language-version +1.3 +-Xexperimental=org.test.ExperimentalAPI +-Xuse-experimental=org.test.ExperimentalAPI diff --git a/compiler/testData/cli/jvm/experimentalAndUseExperimentalWithSameAnnotation.kt b/compiler/testData/cli/jvm/experimentalAndUseExperimentalWithSameAnnotation.kt new file mode 100644 index 00000000000..bed1964610a --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalAndUseExperimentalWithSameAnnotation.kt @@ -0,0 +1,4 @@ +package org.test + +@Experimental(Experimental.Level.ERROR, [Experimental.Impact.COMPILATION]) +annotation class ExperimentalAPI diff --git a/compiler/testData/cli/jvm/experimentalAndUseExperimentalWithSameAnnotation.out b/compiler/testData/cli/jvm/experimentalAndUseExperimentalWithSameAnnotation.out new file mode 100644 index 00000000000..60424dc0d8a --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalAndUseExperimentalWithSameAnnotation.out @@ -0,0 +1,3 @@ +warning: language version 1.3 is experimental, there are no backwards compatibility guarantees for new language and library features +error: '-Xuse-experimental=org.test.ExperimentalAPI' has no effect because '-Xexperimental=org.test.ExperimentalAPI' is used +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/experimentalIsNotAnnotation.args b/compiler/testData/cli/jvm/experimentalIsNotAnnotation.args new file mode 100644 index 00000000000..2188937e234 --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalIsNotAnnotation.args @@ -0,0 +1,5 @@ +$TESTDATA_DIR$/experimentalIsNotAnnotation.kt +-d +$TEMP_DIR$ +-Xexperimental=org.test.NotAnAnnotation1 +-Xuse-experimental=org.test.NotAnAnnotation2 diff --git a/compiler/testData/cli/jvm/experimentalIsNotAnnotation.kt b/compiler/testData/cli/jvm/experimentalIsNotAnnotation.kt new file mode 100644 index 00000000000..c3ffad14bc8 --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalIsNotAnnotation.kt @@ -0,0 +1,4 @@ +package org.test + +enum class NotAnAnnotation1 +interface NotAnAnnotation2 diff --git a/compiler/testData/cli/jvm/experimentalIsNotAnnotation.out b/compiler/testData/cli/jvm/experimentalIsNotAnnotation.out new file mode 100644 index 00000000000..acf9a443420 --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalIsNotAnnotation.out @@ -0,0 +1,3 @@ +error: class org.test.NotAnAnnotation1 is not an experimental API marker annotation +error: class org.test.NotAnAnnotation2 is not an experimental API marker annotation +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/experimentalIsNotMarker.args b/compiler/testData/cli/jvm/experimentalIsNotMarker.args new file mode 100644 index 00000000000..cea647058b2 --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalIsNotMarker.args @@ -0,0 +1,5 @@ +$TESTDATA_DIR$/experimentalIsNotMarker.kt +-d +$TEMP_DIR$ +-Xexperimental=org.test.NotAMarker1 +-Xuse-experimental=org.test.NotAMarker2 diff --git a/compiler/testData/cli/jvm/experimentalIsNotMarker.kt b/compiler/testData/cli/jvm/experimentalIsNotMarker.kt new file mode 100644 index 00000000000..5d2658dcd17 --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalIsNotMarker.kt @@ -0,0 +1,4 @@ +package org.test + +annotation class NotAMarker1 +annotation class NotAMarker2 diff --git a/compiler/testData/cli/jvm/experimentalIsNotMarker.out b/compiler/testData/cli/jvm/experimentalIsNotMarker.out new file mode 100644 index 00000000000..6da2802a9b7 --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalIsNotMarker.out @@ -0,0 +1,3 @@ +error: class org.test.NotAMarker1 is not an experimental API marker annotation +error: class org.test.NotAMarker2 is not an experimental API marker annotation +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/experimentalNested.args b/compiler/testData/cli/jvm/experimentalNested.args new file mode 100644 index 00000000000..89300241959 --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalNested.args @@ -0,0 +1,7 @@ +$TESTDATA_DIR$/experimentalNested.kt +-d +$TEMP_DIR$ +-Xskip-runtime-version-check +-language-version +1.3 +-Xexperimental=org.test.Outer.Nested diff --git a/compiler/testData/cli/jvm/experimentalNested.kt b/compiler/testData/cli/jvm/experimentalNested.kt new file mode 100644 index 00000000000..025420f7ca8 --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalNested.kt @@ -0,0 +1,9 @@ +package org.test + +class Outer { + @Experimental(Experimental.Level.ERROR, [Experimental.Impact.LINKAGE]) + annotation class Nested +} + +@Outer.Nested +fun foo() {} diff --git a/compiler/testData/cli/jvm/experimentalNested.out b/compiler/testData/cli/jvm/experimentalNested.out new file mode 100644 index 00000000000..9d544c3eab0 --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalNested.out @@ -0,0 +1,2 @@ +warning: language version 1.3 is experimental, there are no backwards compatibility guarantees for new language and library features +OK diff --git a/compiler/testData/cli/jvm/experimentalRuntimeScope.args b/compiler/testData/cli/jvm/experimentalRuntimeScope.args new file mode 100644 index 00000000000..59115f70bb5 --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalRuntimeScope.args @@ -0,0 +1,8 @@ +$TESTDATA_DIR$/experimentalRuntimeScope.kt +-d +$TEMP_DIR$ +-Xskip-runtime-version-check +-language-version +1.3 +-Xexperimental=org.test.Experimental1 +-Xuse-experimental=org.test.Experimental2 diff --git a/compiler/testData/cli/jvm/experimentalRuntimeScope.kt b/compiler/testData/cli/jvm/experimentalRuntimeScope.kt new file mode 100644 index 00000000000..fa330fdc079 --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalRuntimeScope.kt @@ -0,0 +1,7 @@ +package org.test + +@Experimental(Experimental.Level.ERROR, [Experimental.Impact.LINKAGE]) +annotation class Experimental1 + +@Experimental(Experimental.Level.ERROR, [Experimental.Impact.RUNTIME]) +annotation class Experimental2 diff --git a/compiler/testData/cli/jvm/experimentalRuntimeScope.out b/compiler/testData/cli/jvm/experimentalRuntimeScope.out new file mode 100644 index 00000000000..7929d5e6ce6 --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalRuntimeScope.out @@ -0,0 +1,3 @@ +warning: language version 1.3 is experimental, there are no backwards compatibility guarantees for new language and library features +error: experimental API marker org.test.Experimental2 has impact other than COMPILATION, therefore it can't be used with -Xuse-experimental +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/experimentalUnresolved.args b/compiler/testData/cli/jvm/experimentalUnresolved.args new file mode 100644 index 00000000000..b164e2b3c85 --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalUnresolved.args @@ -0,0 +1,6 @@ +$TESTDATA_DIR$/experimentalUnresolved.kt +-d +$TEMP_DIR$ +-Xuse-experimental=org.test.Unresolved1 +-Xexperimental=org.test.Unresolved2 +-Xuse-experimental=org.test.Unresolved3 diff --git a/compiler/testData/cli/jvm/experimentalUnresolved.kt b/compiler/testData/cli/jvm/experimentalUnresolved.kt new file mode 100644 index 00000000000..a6e9b3386b9 --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalUnresolved.kt @@ -0,0 +1 @@ +fun test() {} diff --git a/compiler/testData/cli/jvm/experimentalUnresolved.out b/compiler/testData/cli/jvm/experimentalUnresolved.out new file mode 100644 index 00000000000..ee401fe996f --- /dev/null +++ b/compiler/testData/cli/jvm/experimentalUnresolved.out @@ -0,0 +1,4 @@ +error: experimental API marker org.test.Unresolved2 is unresolved. Please make sure it's present in the module dependencies +error: experimental API marker org.test.Unresolved1 is unresolved. Please make sure it's present in the module dependencies +error: experimental API marker org.test.Unresolved3 is unresolved. Please make sure it's present in the module dependencies +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/extraHelp.out b/compiler/testData/cli/jvm/extraHelp.out index bf060957253..fca911a48b2 100644 --- a/compiler/testData/cli/jvm/extraHelp.out +++ b/compiler/testData/cli/jvm/extraHelp.out @@ -44,6 +44,7 @@ where advanced options include: -Xcoroutines={enable|warn|error} Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier -Xeffect-system Enable experimental language feature: effect system + -Xexperimental= Enable and propagate usages of experimental API for marker annotation with the given fully qualified name -Xintellij-plugin-root= Path to the kotlin-compiler.jar or directory where IntelliJ configuration files can be found -Xlegacy-smart-cast-after-try Allow var smart casts despite assignment in try block -Xmulti-platform Enable experimental language support for multi-platform projects @@ -55,6 +56,7 @@ where advanced options include: -Xrepeat= Repeat compilation (for performance analysis) -Xreport-output-files Report source to output files mapping -Xskip-metadata-version-check Load classes with bad metadata version anyway (incl. pre-release classes) + -Xuse-experimental= Enable usages of COMPILATION-affecting experimental API for marker annotation with the given fully qualified name Advanced options are non-standard and may be changed or removed without any notice. OK diff --git a/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java index 96677edea41..8a40976d775 100644 --- a/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java @@ -177,6 +177,42 @@ public class CliTestGenerated extends AbstractCliTest { doJvmTest(fileName); } + @TestMetadata("experimentalAndUseExperimentalWithSameAnnotation.args") + public void testExperimentalAndUseExperimentalWithSameAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/experimentalAndUseExperimentalWithSameAnnotation.args"); + doJvmTest(fileName); + } + + @TestMetadata("experimentalIsNotAnnotation.args") + public void testExperimentalIsNotAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/experimentalIsNotAnnotation.args"); + doJvmTest(fileName); + } + + @TestMetadata("experimentalIsNotMarker.args") + public void testExperimentalIsNotMarker() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/experimentalIsNotMarker.args"); + doJvmTest(fileName); + } + + @TestMetadata("experimentalNested.args") + public void testExperimentalNested() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/experimentalNested.args"); + doJvmTest(fileName); + } + + @TestMetadata("experimentalRuntimeScope.args") + public void testExperimentalRuntimeScope() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/experimentalRuntimeScope.args"); + doJvmTest(fileName); + } + + @TestMetadata("experimentalUnresolved.args") + public void testExperimentalUnresolved() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/experimentalUnresolved.args"); + doJvmTest(fileName); + } + @TestMetadata("extraArgumentPassedInObsoleteForm.args") public void testExtraArgumentPassedInObsoleteForm() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/extraArgumentPassedInObsoleteForm.args"); diff --git a/compiler/util/src/org/jetbrains/kotlin/config/AnalysisFlag.kt b/compiler/util/src/org/jetbrains/kotlin/config/AnalysisFlag.kt index e8a469113a9..91ba3f7b22f 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/AnalysisFlag.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/AnalysisFlag.kt @@ -42,6 +42,10 @@ class AnalysisFlag internal constructor( object Jsr305StateWarnByDefault { operator fun provideDelegate(instance: Any?, property: KProperty<*>) = Flag(property.name, Jsr305State.DEFAULT) } + + object ListOfStrings { + operator fun provideDelegate(instance: Any?, property: KProperty<*>) = Flag(property.name, emptyList()) + } } companion object Flags { @@ -56,5 +60,11 @@ class AnalysisFlag internal constructor( @JvmStatic val allowKotlinPackage by Flag.Boolean + + @JvmStatic + val experimental by Flag.ListOfStrings + + @JvmStatic + val useExperimental by Flag.ListOfStrings } }