From c33b7377da91aec08499aa19f46910bad7fe7a0d Mon Sep 17 00:00:00 2001 From: Dmitry Savvinov Date: Tue, 27 Mar 2018 13:41:03 +0300 Subject: [PATCH] Add support of internal arguments for language feature settings Arguments are passed in form '-XXLanguage:+LanguageFeatureName' for enabling LanguageFeature.LanguageFeatureName, and '-XXLanguage:-LanguageFeatureName' for disabling. Note that they do override other settings, including 'language-version' or extra ('-X') args. --- .../arguments/CommonCompilerArguments.kt | 26 ++++++ .../common/arguments/CommonToolArguments.kt | 2 + .../arguments/InternalCompilerArgument.kt | 87 +++++++++++++++++++ .../arguments/parseCommandLineArguments.kt | 18 +++- .../jetbrains/kotlin/cli/common/CLITool.kt | 39 ++++++--- compiler/testData/cli/jvm/inlineClass.kt | 1 + .../internalArgDisableLanguageFeature.args | 6 ++ .../jvm/internalArgDisableLanguageFeature.out | 14 +++ .../cli/jvm/internalArgEmptyFeatureName.args | 4 + .../cli/jvm/internalArgEmptyFeatureName.out | 14 +++ .../jvm/internalArgEnableLanguageFeature.args | 6 ++ .../jvm/internalArgEnableLanguageFeature.out | 11 +++ .../jvm/internalArgMissingModificator.args | 4 + .../cli/jvm/internalArgMissingModificator.out | 14 +++ .../jvm/internalArgUnrecognizedFeature.args | 4 + .../jvm/internalArgUnrecognizedFeature.out | 14 +++ .../cli/jvm/internalArgWrongPrefix.args | 4 + .../cli/jvm/internalArgWrongPrefix.out | 5 ++ ...internalArgumentOverrideExtraArgument.args | 5 ++ .../internalArgumentOverrideExtraArgument.out | 13 +++ .../CompilerTestLanguageVersionSettings.kt | 2 + .../kotlin/cli/CliTestGenerated.java | 42 +++++++++ .../kotlin/config/LanguageVersionSettings.kt | 29 +++++-- ...utinesDisabledLanguageVersionSettings.java | 5 ++ 24 files changed, 346 insertions(+), 23 deletions(-) create mode 100644 compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/InternalCompilerArgument.kt create mode 100644 compiler/testData/cli/jvm/inlineClass.kt create mode 100644 compiler/testData/cli/jvm/internalArgDisableLanguageFeature.args create mode 100644 compiler/testData/cli/jvm/internalArgDisableLanguageFeature.out create mode 100644 compiler/testData/cli/jvm/internalArgEmptyFeatureName.args create mode 100644 compiler/testData/cli/jvm/internalArgEmptyFeatureName.out create mode 100644 compiler/testData/cli/jvm/internalArgEnableLanguageFeature.args create mode 100644 compiler/testData/cli/jvm/internalArgEnableLanguageFeature.out create mode 100644 compiler/testData/cli/jvm/internalArgMissingModificator.args create mode 100644 compiler/testData/cli/jvm/internalArgMissingModificator.out create mode 100644 compiler/testData/cli/jvm/internalArgUnrecognizedFeature.args create mode 100644 compiler/testData/cli/jvm/internalArgUnrecognizedFeature.out create mode 100644 compiler/testData/cli/jvm/internalArgWrongPrefix.args create mode 100644 compiler/testData/cli/jvm/internalArgWrongPrefix.out create mode 100644 compiler/testData/cli/jvm/internalArgumentOverrideExtraArgument.args create mode 100644 compiler/testData/cli/jvm/internalArgumentOverrideExtraArgument.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 326b2804db3..bd5ac5e7386 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 @@ -230,8 +230,34 @@ abstract class CommonCompilerArguments : CommonToolArguments() { if (!contains(it)) put(it, LanguageFeature.State.ENABLED) } } + + // Internal arguments should go last, because it may be useful to override + // some feature state via -XX (even if some -X flags were passed) + if (internalArguments.isNotEmpty()) { + configureLanguageFeaturesFromInternalArgs(collector) + } } + private fun HashMap.configureLanguageFeaturesFromInternalArgs(collector: MessageCollector) { + val languageSettingsParser = LanguageSettingsParser() + val featuresThatForcePreReleaseBinaries = mutableListOf() + + for (argument in internalArguments) { + val (feature, state) = languageSettingsParser.parseInternalArgument(argument, collector) ?: continue + put(feature, state) + if (state == LanguageFeature.State.ENABLED && feature.forcesPreReleaseBinariesIfEnabled()) { + featuresThatForcePreReleaseBinaries += feature + } + } + + if (featuresThatForcePreReleaseBinaries.isNotEmpty()) { + collector.report( + CompilerMessageSeverity.STRONG_WARNING, + "Following manually enabled features will force generation of pre-release binaries: ${featuresThatForcePreReleaseBinaries.joinToString()}" + ) + } + } + fun configureLanguageVersionSettings(collector: MessageCollector): LanguageVersionSettings { // If only "-api-version" is specified, language version is assumed to be the latest stable diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonToolArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonToolArguments.kt index ed3ec627a03..9a89f90e248 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonToolArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonToolArguments.kt @@ -49,4 +49,6 @@ abstract class CommonToolArguments : Freezable(), Serializable { @GradleOption(DefaultValues.BooleanFalseDefault::class) @Argument(value = "-Werror", description = "Report an error if there are any warnings") var allWarningsAsErrors: Boolean by FreezableVar(false) + + var internalArguments: List by FreezableVar(emptyList()) } diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/InternalCompilerArgument.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/InternalCompilerArgument.kt new file mode 100644 index 00000000000..7030898ae82 --- /dev/null +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/InternalCompilerArgument.kt @@ -0,0 +1,87 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.cli.common.arguments + +import org.jetbrains.kotlin.cli.common.arguments.InternalArgumentParser.Companion.INTERNAL_ARGUMENT_PREFIX +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity +import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.config.LanguageFeature + +/** + * Arguments that can drastically change compiler behavior, + * breaking stability/compatibility. + * + * Internal arguments are split into 'families', each family + * with its own set of arguments, settings and parsing rules + * + * Internal arguments start with '-XX' prefix, followed by + * family name. Everything after that is handled by the corresponding + * parser of that particular family. + */ +interface InternalArgumentParser { + // Should be fast + fun canParse(arg: String): Boolean + + fun parseInternalArgument(arg: String, messageCollector: MessageCollector): A? + + companion object { + internal const val INTERNAL_ARGUMENT_PREFIX = "-XX" + + internal val PARSERS: List> = listOf( + LanguageSettingsParser() + ) + } +} + +abstract class AbstractInternalArgumentParser(familyName: String) : InternalArgumentParser { + private val wholePrefix: String = INTERNAL_ARGUMENT_PREFIX + familyName + + override fun canParse(arg: String): Boolean = arg.startsWith(wholePrefix) + + override fun parseInternalArgument(arg: String, messageCollector: MessageCollector): A? { + if (!arg.startsWith(wholePrefix)) return null + + return parseTail(arg.removePrefix(wholePrefix), arg, messageCollector) + } + + abstract fun parseTail(tail: String, wholeArgument: String, messageCollector: MessageCollector): A? +} + + +// Arguments of form '-XXLanguage:+LanguageFeature' or '-XXLanguage:-LanguageFeature', which enable or disable corresponding LanguageFeature. +class LanguageSettingsParser : AbstractInternalArgumentParser("Language") { + + // Expected tail form: ':(+|-)' + override fun parseTail(tail: String, wholeArgument: String, messageCollector: MessageCollector): ManualLanguageFeatureSetting? { + fun reportAndReturnNull(message: String): Nothing? { + messageCollector.report(CompilerMessageSeverity.STRONG_WARNING, message) + return null + } + + val colon = tail.getOrNull(0) ?: return reportAndReturnNull("Incorrect internal argument syntax, missing colon: $wholeArgument") + + val modificator = tail.getOrNull(1) + val languageFeatureState = when (modificator) { + '+' -> LanguageFeature.State.ENABLED + + '-' -> LanguageFeature.State.DISABLED + + else -> return reportAndReturnNull("Incorrect internal argument syntax, missing modificator: $wholeArgument") + } + + val languageFeatureName = tail.substring(2) + if (languageFeatureName.isEmpty()) return reportAndReturnNull("Empty language feature name for internal argument '$wholeArgument'") + + val languageFeature = LanguageFeature.fromString(languageFeatureName) + ?: return reportAndReturnNull("Unknown language feature '$languageFeatureName' in passed internal argument '$wholeArgument'") + + return ManualLanguageFeatureSetting(languageFeature, languageFeatureState) + } +} + +interface InternalArgument + +data class ManualLanguageFeatureSetting(val languageFeature: LanguageFeature, val state: LanguageFeature.State) : InternalArgument \ No newline at end of file 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 540b480e6a0..016ba600ce9 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 @@ -19,7 +19,6 @@ package org.jetbrains.kotlin.cli.common.arguments import org.jetbrains.kotlin.utils.SmartList import kotlin.reflect.KClass import kotlin.reflect.KMutableProperty1 -import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.memberProperties @Target(AnnotationTarget.PROPERTY) @@ -102,6 +101,7 @@ fun parseCommandLineArguments(args: List, resu } val freeArgs = ArrayList() + val internalArguments = ArrayList() var i = 0 loop@ while (i < args.size) { @@ -116,6 +116,21 @@ fun parseCommandLineArguments(args: List, resu continue } + if (arg.startsWith(InternalArgumentParser.INTERNAL_ARGUMENT_PREFIX)) { + val matchingParsers = InternalArgumentParser.PARSERS.filter { it.canParse(arg) } + assert(matchingParsers.size <= 1) { "Internal error: internal argument $arg can be ambiguously parsed by parsers ${matchingParsers.joinToString()}" } + + val parser = matchingParsers.firstOrNull() + + if (parser == null) { + errors.unknownExtraFlags += arg + } else { + internalArguments.add(arg) + } + + continue + } + val argumentField = properties.firstOrNull { it.matches(arg) } if (argumentField == null) { when { @@ -154,6 +169,7 @@ fun parseCommandLineArguments(args: List, resu } result.freeArgs += freeArgs + result.internalArguments += internalArguments } private fun updateField(property: KMutableProperty1, result: A, value: Any, delimiter: String) { diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLITool.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLITool.kt index 8662cb5901e..9d74d8e2e5b 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLITool.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLITool.kt @@ -38,10 +38,10 @@ abstract class CLITool { } protected fun exec( - errStream: PrintStream, - services: Services, - messageRenderer: MessageRenderer, - args: Array + errStream: PrintStream, + services: Services, + messageRenderer: MessageRenderer, + args: Array ): ExitCode { val arguments = createArguments() parseCommandLineArguments(args.asList(), arguments) @@ -67,8 +67,7 @@ abstract class CLITool { } return exec(collector, services, arguments) - } - finally { + } finally { errStream.print(messageRenderer.renderConclusion()) if (PlainTextMessageRenderer.COLOR_ENABLED) { @@ -84,12 +83,11 @@ abstract class CLITool { val fixedMessageCollector = if (arguments.suppressWarnings && !arguments.allWarningsAsErrors) { FilteringMessageCollector(messageCollector, Predicate.isEqual(CompilerMessageSeverity.WARNING)) - } - else { + } else { messageCollector } - reportArgumentParseProblems(fixedMessageCollector, arguments.errors) + reportArgumentParseProblems(fixedMessageCollector, arguments) return execImpl(fixedMessageCollector, services, arguments) } @@ -117,13 +115,16 @@ abstract class CLITool { } } - private fun reportArgumentParseProblems(collector: MessageCollector, errors: ArgumentParseErrors) { + private fun reportArgumentParseProblems(collector: MessageCollector, arguments: A) { + val errors = arguments.errors for (flag in errors.unknownExtraFlags) { collector.report(STRONG_WARNING, "Flag is not supported by this version of the compiler: $flag") } for (argument in errors.extraArgumentsPassedInObsoleteForm) { - collector.report(STRONG_WARNING, "Advanced option value is passed in an obsolete form. Please use the '=' character " + - "to specify the value: $argument=...") + collector.report( + STRONG_WARNING, "Advanced option value is passed in an obsolete form. Please use the '=' character " + + "to specify the value: $argument=..." + ) } for ((key, value) in errors.duplicateArguments) { collector.report(STRONG_WARNING, "Argument $key is passed multiple times. Only the last value will be used: $value") @@ -131,6 +132,17 @@ abstract class CLITool { for ((deprecatedName, newName) in errors.deprecatedArguments) { collector.report(STRONG_WARNING, "Argument $deprecatedName is deprecated. Please use $newName instead") } + if (arguments.internalArguments.isNotEmpty()) { + collector.report( + STRONG_WARNING, + "ATTENTION!\n" + + "This build uses internal compiler arguments:\n" + + arguments.internalArguments.joinToString(prefix = "\n", postfix = "\n\n", separator = "\n") + + "This mode is strictly prohibited for production use,\n" + + "as no stability/compatibility guarantees are given on\n" + + "compiler or generated code. Use it at your own risk!\n" + ) + } } private fun printVersionIfNeeded(messageCollector: MessageCollector, arguments: A) { @@ -166,8 +178,7 @@ abstract class CLITool { fun doMainNoExit(compiler: CLITool<*>, args: Array): ExitCode { try { return compiler.exec(System.err, *args) - } - catch (e: CompileEnvironmentException) { + } catch (e: CompileEnvironmentException) { System.err.println(e.message) return ExitCode.INTERNAL_ERROR } diff --git a/compiler/testData/cli/jvm/inlineClass.kt b/compiler/testData/cli/jvm/inlineClass.kt new file mode 100644 index 00000000000..95fa97a3515 --- /dev/null +++ b/compiler/testData/cli/jvm/inlineClass.kt @@ -0,0 +1 @@ +inline class Foo(val x: Int) \ No newline at end of file diff --git a/compiler/testData/cli/jvm/internalArgDisableLanguageFeature.args b/compiler/testData/cli/jvm/internalArgDisableLanguageFeature.args new file mode 100644 index 00000000000..99aa09deb41 --- /dev/null +++ b/compiler/testData/cli/jvm/internalArgDisableLanguageFeature.args @@ -0,0 +1,6 @@ +-language-version +1.3 +-XXLanguage\:-InlineClasses +$TESTDATA_DIR$/inlineClass.kt +-d +$TEMP_DIR$ \ No newline at end of file diff --git a/compiler/testData/cli/jvm/internalArgDisableLanguageFeature.out b/compiler/testData/cli/jvm/internalArgDisableLanguageFeature.out new file mode 100644 index 00000000000..21e12da51c6 --- /dev/null +++ b/compiler/testData/cli/jvm/internalArgDisableLanguageFeature.out @@ -0,0 +1,14 @@ +warning: ATTENTION! +This build uses internal compiler arguments: + +-XXLanguage:-InlineClasses + +This mode is strictly prohibited for production use, +as no stability/compatibility guarantees are given on +compiler or generated code. Use it at your own risk! + +warning: language version 1.3 is experimental, there are no backwards compatibility guarantees for new language and library features +compiler/testData/cli/jvm/inlineClass.kt:1:1: error: the feature "inline classes" is experimental and should be enabled explicitly +inline class Foo(val x: Int) +^ +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/internalArgEmptyFeatureName.args b/compiler/testData/cli/jvm/internalArgEmptyFeatureName.args new file mode 100644 index 00000000000..fbab8506710 --- /dev/null +++ b/compiler/testData/cli/jvm/internalArgEmptyFeatureName.args @@ -0,0 +1,4 @@ +$TESTDATA_DIR$/inlineClass.kt +-d +$TEMP_DIR$ +-XXLanguage\:+ \ No newline at end of file diff --git a/compiler/testData/cli/jvm/internalArgEmptyFeatureName.out b/compiler/testData/cli/jvm/internalArgEmptyFeatureName.out new file mode 100644 index 00000000000..9c2a1e3c1a8 --- /dev/null +++ b/compiler/testData/cli/jvm/internalArgEmptyFeatureName.out @@ -0,0 +1,14 @@ +warning: ATTENTION! +This build uses internal compiler arguments: + +-XXLanguage:+ + +This mode is strictly prohibited for production use, +as no stability/compatibility guarantees are given on +compiler or generated code. Use it at your own risk! + +warning: empty language feature name for internal argument '-XXLanguage:+' +compiler/testData/cli/jvm/inlineClass.kt:1:1: error: the feature "inline classes" is experimental and should be enabled explicitly +inline class Foo(val x: Int) +^ +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/internalArgEnableLanguageFeature.args b/compiler/testData/cli/jvm/internalArgEnableLanguageFeature.args new file mode 100644 index 00000000000..a1a797d3fce --- /dev/null +++ b/compiler/testData/cli/jvm/internalArgEnableLanguageFeature.args @@ -0,0 +1,6 @@ +$TESTDATA_DIR$/inlineClass.kt +-d +$TEMP_DIR$ +-language-version +1.2 +-XXLanguage\:+InlineClasses \ No newline at end of file diff --git a/compiler/testData/cli/jvm/internalArgEnableLanguageFeature.out b/compiler/testData/cli/jvm/internalArgEnableLanguageFeature.out new file mode 100644 index 00000000000..9cb34f0a165 --- /dev/null +++ b/compiler/testData/cli/jvm/internalArgEnableLanguageFeature.out @@ -0,0 +1,11 @@ +warning: ATTENTION! +This build uses internal compiler arguments: + +-XXLanguage:+InlineClasses + +This mode is strictly prohibited for production use, +as no stability/compatibility guarantees are given on +compiler or generated code. Use it at your own risk! + +warning: following manually enabled features will force generation of pre-release binaries: InlineClasses +OK diff --git a/compiler/testData/cli/jvm/internalArgMissingModificator.args b/compiler/testData/cli/jvm/internalArgMissingModificator.args new file mode 100644 index 00000000000..7a0d2d6226a --- /dev/null +++ b/compiler/testData/cli/jvm/internalArgMissingModificator.args @@ -0,0 +1,4 @@ +$TESTDATA_DIR$/inlineClass.kt +-d +$TEMP_DIR$ +-XXLanguage\:InlineClasses \ No newline at end of file diff --git a/compiler/testData/cli/jvm/internalArgMissingModificator.out b/compiler/testData/cli/jvm/internalArgMissingModificator.out new file mode 100644 index 00000000000..e8ec00c3208 --- /dev/null +++ b/compiler/testData/cli/jvm/internalArgMissingModificator.out @@ -0,0 +1,14 @@ +warning: ATTENTION! +This build uses internal compiler arguments: + +-XXLanguage:InlineClasses + +This mode is strictly prohibited for production use, +as no stability/compatibility guarantees are given on +compiler or generated code. Use it at your own risk! + +warning: incorrect internal argument syntax, missing modificator: -XXLanguage:InlineClasses +compiler/testData/cli/jvm/inlineClass.kt:1:1: error: the feature "inline classes" is experimental and should be enabled explicitly +inline class Foo(val x: Int) +^ +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/internalArgUnrecognizedFeature.args b/compiler/testData/cli/jvm/internalArgUnrecognizedFeature.args new file mode 100644 index 00000000000..b67811122ff --- /dev/null +++ b/compiler/testData/cli/jvm/internalArgUnrecognizedFeature.args @@ -0,0 +1,4 @@ +$TESTDATA_DIR$/inlineClass.kt +-d +$TEMP_DIR$ +-XXLanguage\:+UnknownFeature \ No newline at end of file diff --git a/compiler/testData/cli/jvm/internalArgUnrecognizedFeature.out b/compiler/testData/cli/jvm/internalArgUnrecognizedFeature.out new file mode 100644 index 00000000000..0f250a38c60 --- /dev/null +++ b/compiler/testData/cli/jvm/internalArgUnrecognizedFeature.out @@ -0,0 +1,14 @@ +warning: ATTENTION! +This build uses internal compiler arguments: + +-XXLanguage:+UnknownFeature + +This mode is strictly prohibited for production use, +as no stability/compatibility guarantees are given on +compiler or generated code. Use it at your own risk! + +warning: unknown language feature 'UnknownFeature' in passed internal argument '-XXLanguage:+UnknownFeature' +compiler/testData/cli/jvm/inlineClass.kt:1:1: error: the feature "inline classes" is experimental and should be enabled explicitly +inline class Foo(val x: Int) +^ +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/internalArgWrongPrefix.args b/compiler/testData/cli/jvm/internalArgWrongPrefix.args new file mode 100644 index 00000000000..15d38d6f53e --- /dev/null +++ b/compiler/testData/cli/jvm/internalArgWrongPrefix.args @@ -0,0 +1,4 @@ +$TESTDATA_DIR$/inlineClass.kt +-d +$TEMP_DIR$ +-XX:+InlineClasses \ No newline at end of file diff --git a/compiler/testData/cli/jvm/internalArgWrongPrefix.out b/compiler/testData/cli/jvm/internalArgWrongPrefix.out new file mode 100644 index 00000000000..75b3f45ce91 --- /dev/null +++ b/compiler/testData/cli/jvm/internalArgWrongPrefix.out @@ -0,0 +1,5 @@ +warning: flag is not supported by this version of the compiler: -XX:+InlineClasses +compiler/testData/cli/jvm/inlineClass.kt:1:1: error: the feature "inline classes" is experimental and should be enabled explicitly +inline class Foo(val x: Int) +^ +COMPILATION_ERROR diff --git a/compiler/testData/cli/jvm/internalArgumentOverrideExtraArgument.args b/compiler/testData/cli/jvm/internalArgumentOverrideExtraArgument.args new file mode 100644 index 00000000000..b1d825c2f97 --- /dev/null +++ b/compiler/testData/cli/jvm/internalArgumentOverrideExtraArgument.args @@ -0,0 +1,5 @@ +$TESTDATA_DIR$/legacySmartCastsAfterTry.kt +-d +$TEMP_DIR$ +-XXLanguage\:+SoundSmartCastsAfterTry +-Xlegacy-smart-cast-after-try diff --git a/compiler/testData/cli/jvm/internalArgumentOverrideExtraArgument.out b/compiler/testData/cli/jvm/internalArgumentOverrideExtraArgument.out new file mode 100644 index 00000000000..44005ca52e5 --- /dev/null +++ b/compiler/testData/cli/jvm/internalArgumentOverrideExtraArgument.out @@ -0,0 +1,13 @@ +warning: ATTENTION! +This build uses internal compiler arguments: + +-XXLanguage:+SoundSmartCastsAfterTry + +This mode is strictly prohibited for production use, +as no stability/compatibility guarantees are given on +compiler or generated code. Use it at your own risk! + +compiler/testData/cli/jvm/legacySmartCastsAfterTry.kt:8:9: error: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String? + some.length + ^ +COMPILATION_ERROR diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/CompilerTestLanguageVersionSettings.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/CompilerTestLanguageVersionSettings.kt index 5f481bf3383..2446892e6fc 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/CompilerTestLanguageVersionSettings.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/CompilerTestLanguageVersionSettings.kt @@ -42,6 +42,8 @@ data class CompilerTestLanguageVersionSettings( override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State = languageFeatures[feature] ?: delegate.getFeatureSupport(feature) + override fun isPreRelease(): Boolean = languageVersion.isPreRelease() + @Suppress("UNCHECKED_CAST") override fun getFlag(flag: AnalysisFlag): T = analysisFlags[flag] as T? ?: flag.defaultValue } diff --git a/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java index 98d1a5f8427..d6e95eae265 100644 --- a/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java @@ -232,6 +232,48 @@ public class CliTestGenerated extends AbstractCliTest { runTest("compiler/testData/cli/jvm/inlineCycle.args"); } + @TestMetadata("internalArgDisableLanguageFeature.args") + public void testInternalArgDisableLanguageFeature() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/internalArgDisableLanguageFeature.args"); + doJvmTest(fileName); + } + + @TestMetadata("internalArgEmptyFeatureName.args") + public void testInternalArgEmptyFeatureName() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/internalArgEmptyFeatureName.args"); + doJvmTest(fileName); + } + + @TestMetadata("internalArgEnableLanguageFeature.args") + public void testInternalArgEnableLanguageFeature() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/internalArgEnableLanguageFeature.args"); + doJvmTest(fileName); + } + + @TestMetadata("internalArgMissingModificator.args") + public void testInternalArgMissingModificator() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/internalArgMissingModificator.args"); + doJvmTest(fileName); + } + + @TestMetadata("internalArgUnrecognizedFeature.args") + public void testInternalArgUnrecognizedFeature() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/internalArgUnrecognizedFeature.args"); + doJvmTest(fileName); + } + + @TestMetadata("internalArgWrongPrefix.args") + public void testInternalArgWrongPrefix() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/internalArgWrongPrefix.args"); + doJvmTest(fileName); + } + + @TestMetadata("internalArgumentOverrideExtraArgument.args") + public void testInternalArgumentOverrideExtraArgument() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/jvm/internalArgumentOverrideExtraArgument.args"); + doJvmTest(fileName); + } + @TestMetadata("javaSrcWrongPackage.args") public void testJavaSrcWrongPackage() throws Exception { runTest("compiler/testData/cli/jvm/javaSrcWrongPackage.args"); diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 35ac72947b9..fcf72db8541 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -14,6 +14,7 @@ enum class LanguageFeature( val sinceApiVersion: ApiVersion = ApiVersion.KOTLIN_1_0, val hintUrl: String? = null, val defaultState: State = State.ENABLED, + val forcesPreReleaseBinaries: Boolean = false, val enabledInProgressiveMode: Boolean = false ) { // Note: names of these entries are also used in diagnostic tests and in user-visible messages (see presentableText below) @@ -65,14 +66,14 @@ enum class LanguageFeature( ProperVisibilityForCompanionObjectInstanceField(KOTLIN_1_3, enabledInProgressiveMode = true), ProperForInArrayLoopRangeVariableAssignmentSemantic(KOTLIN_1_3, enabledInProgressiveMode = true), NestedClassesInAnnotations(KOTLIN_1_3), - JvmStaticInInterface(KOTLIN_1_3), + JvmStaticInInterface(KOTLIN_1_3, forcesPreReleaseBinaries = true), ProhibitVisibilityOfNestedClassifiersFromSupertypesOfCompanion(KOTLIN_1_3, enabledInProgressiveMode = true), ProhibitNonConstValuesAsVarargsInAnnotations(KOTLIN_1_3, enabledInProgressiveMode = true), - ReleaseCoroutines(KOTLIN_1_3), + ReleaseCoroutines(KOTLIN_1_3, forcesPreReleaseBinaries = true), ReadDeserializedContracts(KOTLIN_1_3), UseReturnsEffect(KOTLIN_1_3), UseCallsInPlaceEffect(KOTLIN_1_3), - AllowContractsForCustomFunctions(KOTLIN_1_3), + AllowContractsForCustomFunctions(KOTLIN_1_3, forcesPreReleaseBinaries = true), ProhibitLocalAnnotations(KOTLIN_1_3, enabledInProgressiveMode = true), StrictJavaNullabilityAssertions(sinceVersion = null, defaultState = State.DISABLED), @@ -90,7 +91,7 @@ enum class LanguageFeature( NewInference(sinceVersion = KOTLIN_1_3, defaultState = State.DISABLED), - InlineClasses(sinceVersion = null, defaultState = State.DISABLED), + InlineClasses(sinceVersion = null, defaultState = State.DISABLED, forcesPreReleaseBinaries = true), ; @@ -147,7 +148,12 @@ interface LanguageVersionSettings { fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State fun supportsFeature(feature: LanguageFeature): Boolean = - getFeatureSupport(feature).let { it == LanguageFeature.State.ENABLED || it == LanguageFeature.State.ENABLED_WITH_WARNING } + getFeatureSupport(feature).let { + it == LanguageFeature.State.ENABLED || + it == LanguageFeature.State.ENABLED_WITH_WARNING + } + + fun isPreRelease(): Boolean fun getFlag(flag: AnalysisFlag): T @@ -192,17 +198,24 @@ class LanguageVersionSettingsImpl @JvmOverloads constructor( } } + override fun isPreRelease(): Boolean = languageVersion.isPreRelease() || + specificFeatures.any { (feature, state) -> + state == LanguageFeature.State.ENABLED && feature.forcesPreReleaseBinariesIfEnabled() + } + companion object { @JvmField val DEFAULT = LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE) } } -fun LanguageVersionSettings.isPreRelease(): Boolean = - languageVersion.isPreRelease() - fun LanguageVersion.isPreRelease(): Boolean { if (!isStable) return true return KotlinCompilerVersion.isPreRelease() && this == LanguageVersion.LATEST_STABLE } + +fun LanguageFeature.forcesPreReleaseBinariesIfEnabled(): Boolean { + val isFeatureNotReleasedYet = sinceVersion?.isStable != true + return isFeatureNotReleasedYet && forcesPreReleaseBinaries +} diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/config/ReleaseCoroutinesDisabledLanguageVersionSettings.java b/js/js.frontend/src/org/jetbrains/kotlin/js/config/ReleaseCoroutinesDisabledLanguageVersionSettings.java index 852bcf4c5ec..e43296daeef 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/config/ReleaseCoroutinesDisabledLanguageVersionSettings.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/config/ReleaseCoroutinesDisabledLanguageVersionSettings.java @@ -25,6 +25,11 @@ public class ReleaseCoroutinesDisabledLanguageVersionSettings implements Languag return delegate.getFeatureSupport(feature); } + @Override + public boolean isPreRelease() { + return delegate.isPreRelease(); + } + @Override public T getFlag(@NotNull AnalysisFlag flag) { return delegate.getFlag(flag);