Refactor language feature settings processing for exposing it outside of the CLI compiler
This commit is contained in:
+82
-1
@@ -17,8 +17,9 @@
|
||||
package org.jetbrains.kotlin.cli.common.arguments
|
||||
|
||||
import com.intellij.util.xmlb.annotations.Transient
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.config.AnalysisFlag
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import java.util.*
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@@ -164,9 +165,89 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
|
||||
put(AnalysisFlag.allowKotlinPackage, allowKotlinPackage)
|
||||
put(AnalysisFlag.experimental, experimental?.toList().orEmpty())
|
||||
put(AnalysisFlag.useExperimental, useExperimental?.toList().orEmpty())
|
||||
put(AnalysisFlag.explicitApiVersion, apiVersion != null)
|
||||
}
|
||||
}
|
||||
|
||||
open fun configureLanguageFeatures(collector: MessageCollector): MutableMap<LanguageFeature, LanguageFeature.State> =
|
||||
HashMap<LanguageFeature, LanguageFeature.State>().apply {
|
||||
if (multiPlatform) {
|
||||
put(LanguageFeature.MultiPlatformProjects, LanguageFeature.State.ENABLED)
|
||||
}
|
||||
|
||||
when (coroutinesState) {
|
||||
CommonCompilerArguments.ERROR -> put(LanguageFeature.Coroutines, LanguageFeature.State.ENABLED_WITH_ERROR)
|
||||
CommonCompilerArguments.ENABLE -> put(LanguageFeature.Coroutines, LanguageFeature.State.ENABLED)
|
||||
CommonCompilerArguments.WARN -> {}
|
||||
else -> {
|
||||
val message = "Invalid value of -Xcoroutines (should be: enable, warn or error): " + coroutinesState
|
||||
collector.report(CompilerMessageSeverity.ERROR, message, null)
|
||||
}
|
||||
}
|
||||
|
||||
if (newInference) {
|
||||
put(LanguageFeature.NewInference, LanguageFeature.State.ENABLED)
|
||||
}
|
||||
|
||||
if (legacySmartCastAfterTry) {
|
||||
put(LanguageFeature.SoundSmartCastsAfterTry, LanguageFeature.State.DISABLED)
|
||||
}
|
||||
|
||||
if (effectSystem) {
|
||||
put(LanguageFeature.UseCallsInPlaceEffect, LanguageFeature.State.ENABLED)
|
||||
put(LanguageFeature.UseReturnsEffect, LanguageFeature.State.ENABLED)
|
||||
}
|
||||
|
||||
if (readDeserializedContracts) {
|
||||
put(LanguageFeature.ReadDeserializedContracts, LanguageFeature.State.ENABLED)
|
||||
}
|
||||
|
||||
if (properIeee754Comparisons) {
|
||||
put(LanguageFeature.ProperIeee754Comparisons, LanguageFeature.State.ENABLED)
|
||||
}
|
||||
}
|
||||
|
||||
fun configureLanguageVersionSettings(collector: MessageCollector): LanguageVersionSettings {
|
||||
|
||||
// If only "-api-version" is specified, language version is assumed to be the latest stable
|
||||
val languageVersion = parseVersion(collector, languageVersion, "language") ?: LanguageVersion.LATEST_STABLE
|
||||
|
||||
// If only "-language-version" is specified, API version is assumed to be equal to the language version
|
||||
// (API version cannot be greater than the language version)
|
||||
val apiVersion = parseVersion(collector, apiVersion, "API") ?: languageVersion
|
||||
|
||||
if (apiVersion > languageVersion) {
|
||||
collector.report(
|
||||
CompilerMessageSeverity.ERROR,
|
||||
"-api-version (${apiVersion.versionString}) cannot be greater than -language-version (${languageVersion.versionString})"
|
||||
)
|
||||
}
|
||||
|
||||
if (!languageVersion.isStable) {
|
||||
collector.report(
|
||||
CompilerMessageSeverity.STRONG_WARNING,
|
||||
"Language version ${languageVersion.versionString} is experimental, there are no backwards compatibility guarantees for new language and library features"
|
||||
)
|
||||
}
|
||||
|
||||
return LanguageVersionSettingsImpl(
|
||||
languageVersion,
|
||||
ApiVersion.createByLanguageVersion(apiVersion),
|
||||
configureAnalysisFlags(collector),
|
||||
configureLanguageFeatures(collector)
|
||||
)
|
||||
}
|
||||
|
||||
private fun parseVersion(collector: MessageCollector, value: String?, versionOf: String): LanguageVersion? =
|
||||
if (value == null) null
|
||||
else LanguageVersion.fromVersionString(value)
|
||||
?: run {
|
||||
val versionStrings = LanguageVersion.values().map(LanguageVersion::description)
|
||||
val message = "Unknown $versionOf version: $value\nSupported $versionOf versions: ${versionStrings.joinToString(", ")}"
|
||||
collector.report(CompilerMessageSeverity.ERROR, message, null)
|
||||
null
|
||||
}
|
||||
|
||||
// Used only for serialize and deserialize settings. Don't use in other places!
|
||||
class DummyImpl : CommonCompilerArguments()
|
||||
}
|
||||
|
||||
+9
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.config.AnalysisFlag
|
||||
import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
|
||||
class K2JVMCompilerArguments : CommonCompilerArguments() {
|
||||
companion object {
|
||||
@@ -235,4 +236,12 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
override fun configureLanguageFeatures(collector: MessageCollector): MutableMap<LanguageFeature, LanguageFeature.State> {
|
||||
val result = super.configureLanguageFeatures(collector)
|
||||
if (strictJavaNullabilityAssertions) {
|
||||
result[LanguageFeature.StrictJavaNullabilityAssertions] = LanguageFeature.State.ENABLED
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ import org.jetbrains.kotlin.utils.StringsKt;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -162,89 +161,10 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> extends CLI
|
||||
}
|
||||
|
||||
private void setupLanguageVersionSettings(@NotNull CompilerConfiguration configuration, @NotNull A arguments) {
|
||||
LanguageVersion languageVersion = parseVersion(configuration, arguments.getLanguageVersion(), "language");
|
||||
LanguageVersion apiVersion = parseVersion(configuration, arguments.getApiVersion(), "API");
|
||||
|
||||
if (languageVersion != null || apiVersion != null) {
|
||||
configuration.put(CLIConfigurationKeys.IS_API_VERSION_EXPLICIT, true);
|
||||
}
|
||||
|
||||
if (languageVersion == null) {
|
||||
// If no "-language-version" is specified, language version is assumed to be the latest stable
|
||||
languageVersion = LanguageVersion.LATEST_STABLE;
|
||||
}
|
||||
|
||||
if (apiVersion == null) {
|
||||
// If no "-api-version" is specified, API version is assumed to be equal to the language version
|
||||
// (API version cannot be greater than the language version)
|
||||
apiVersion = languageVersion;
|
||||
}
|
||||
|
||||
MessageCollector collector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY);
|
||||
if (apiVersion.compareTo(languageVersion) > 0) {
|
||||
collector.report(
|
||||
ERROR,
|
||||
"-api-version (" + apiVersion.getVersionString() + ") cannot be greater than " +
|
||||
"-language-version (" + languageVersion.getVersionString() + ")",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
if (!languageVersion.isStable()) {
|
||||
collector.report(
|
||||
STRONG_WARNING,
|
||||
"Language version " + languageVersion.getVersionString() + " is experimental, there are " +
|
||||
"no backwards compatibility guarantees for new language and library features",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
Map<LanguageFeature, LanguageFeature.State> extraLanguageFeatures = new HashMap<>(0);
|
||||
if (arguments.getMultiPlatform()) {
|
||||
extraLanguageFeatures.put(LanguageFeature.MultiPlatformProjects, LanguageFeature.State.ENABLED);
|
||||
}
|
||||
|
||||
LanguageFeature.State coroutinesState = chooseCoroutinesApplicabilityLevel(configuration, arguments);
|
||||
if (coroutinesState != null) {
|
||||
extraLanguageFeatures.put(LanguageFeature.Coroutines, coroutinesState);
|
||||
}
|
||||
|
||||
if (arguments.getNewInference()) {
|
||||
extraLanguageFeatures.put(LanguageFeature.NewInference, LanguageFeature.State.ENABLED);
|
||||
}
|
||||
|
||||
if (arguments.getLegacySmartCastAfterTry()) {
|
||||
extraLanguageFeatures.put(LanguageFeature.SoundSmartCastsAfterTry, LanguageFeature.State.DISABLED);
|
||||
}
|
||||
|
||||
if (arguments.getEffectSystem()) {
|
||||
extraLanguageFeatures.put(LanguageFeature.UseCallsInPlaceEffect, LanguageFeature.State.ENABLED);
|
||||
extraLanguageFeatures.put(LanguageFeature.UseReturnsEffect, LanguageFeature.State.ENABLED);
|
||||
}
|
||||
|
||||
if (arguments.getReadDeserializedContracts()) {
|
||||
extraLanguageFeatures.put(LanguageFeature.ReadDeserializedContracts, LanguageFeature.State.ENABLED);
|
||||
}
|
||||
|
||||
if (arguments.getProperIeee754Comparisons()) {
|
||||
extraLanguageFeatures.put(LanguageFeature.ProperIeee754Comparisons, LanguageFeature.State.ENABLED);
|
||||
}
|
||||
|
||||
setupPlatformSpecificLanguageFeatureSettings(extraLanguageFeatures, arguments);
|
||||
|
||||
CommonConfigurationKeysKt.setLanguageVersionSettings(configuration, new LanguageVersionSettingsImpl(
|
||||
languageVersion,
|
||||
ApiVersion.createByLanguageVersion(apiVersion),
|
||||
arguments.configureAnalysisFlags(collector),
|
||||
extraLanguageFeatures
|
||||
));
|
||||
}
|
||||
|
||||
protected void setupPlatformSpecificLanguageFeatureSettings(
|
||||
@NotNull Map<LanguageFeature, LanguageFeature.State> extraLanguageFeatures,
|
||||
@NotNull A commandLineArguments
|
||||
) {
|
||||
// do nothing
|
||||
CommonConfigurationKeysKt.setLanguageVersionSettings(configuration, arguments.configureLanguageVersionSettings(collector));
|
||||
}
|
||||
|
||||
private static final String kotlinHomeEnvVar = System.getenv(KOTLIN_HOME_ENV_VAR);
|
||||
@@ -299,43 +219,6 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> extends CLI
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static LanguageFeature.State chooseCoroutinesApplicabilityLevel(
|
||||
@NotNull CompilerConfiguration configuration,
|
||||
@NotNull CommonCompilerArguments arguments
|
||||
) {
|
||||
switch (arguments.getCoroutinesState()) {
|
||||
case CommonCompilerArguments.ERROR:
|
||||
return LanguageFeature.State.ENABLED_WITH_ERROR;
|
||||
case CommonCompilerArguments.ENABLE:
|
||||
return LanguageFeature.State.ENABLED;
|
||||
case CommonCompilerArguments.WARN:
|
||||
return null;
|
||||
default:
|
||||
String message = "Invalid value of -Xcoroutines (should be: enable, warn or error): " + arguments.getCoroutinesState();
|
||||
configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(ERROR, message, null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static LanguageVersion parseVersion(
|
||||
@NotNull CompilerConfiguration configuration, @Nullable String value, @NotNull String versionOf
|
||||
) {
|
||||
if (value == null) return null;
|
||||
|
||||
LanguageVersion version = LanguageVersion.fromVersionString(value);
|
||||
if (version != null) {
|
||||
return version;
|
||||
}
|
||||
|
||||
List<String> versionStrings = ArraysKt.map(LanguageVersion.values(), LanguageVersion::getDescription);
|
||||
String message = "Unknown " + versionOf + " version: " + value + "\n" +
|
||||
"Supported " + versionOf + " versions: " + StringsKt.join(versionStrings, ", ");
|
||||
configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(ERROR, message, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
protected abstract void setupPlatformSpecificArgumentsAndServices(
|
||||
@NotNull CompilerConfiguration configuration, @NotNull A arguments, @NotNull Services services
|
||||
);
|
||||
|
||||
@@ -29,8 +29,6 @@ public class CLIConfigurationKeys {
|
||||
CompilerConfigurationKey.create("allow kotlin package");
|
||||
public static final CompilerConfigurationKey<Boolean> REPORT_PERF =
|
||||
CompilerConfigurationKey.create("report performance information");
|
||||
public static final CompilerConfigurationKey<Boolean> IS_API_VERSION_EXPLICIT =
|
||||
CompilerConfigurationKey.create("is API version explicit");
|
||||
|
||||
// Used in Eclipse plugin (see KotlinCLICompiler)
|
||||
public static final CompilerConfigurationKey<String> INTELLIJ_PLUGIN_ROOT =
|
||||
|
||||
+1
-1
@@ -129,7 +129,7 @@ object JvmRuntimeVersionsConsistencyChecker {
|
||||
val actualApi = ApiVersion.parse(actualRuntimeVersion.toString())
|
||||
if (actualApi == null) {
|
||||
messageCollector.issue(null, "Could not parse runtime JAR version: $actualRuntimeVersion")
|
||||
} else if (!configuration.getBoolean(CLIConfigurationKeys.IS_API_VERSION_EXPLICIT) && actualApi < currentApi) {
|
||||
} else if (!languageVersionSettings.getFlag(AnalysisFlag.explicitApiVersion) && actualApi < currentApi) {
|
||||
// If there's no explicit "-api-version" AND there's an old stdlib in the classpath (older than the default value of API),
|
||||
// we infer API = the version of that stdlib.
|
||||
// Note that "no explicit -api-version" requirement is necessary because for example, in
|
||||
|
||||
@@ -227,17 +227,6 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun setupPlatformSpecificLanguageFeatureSettings(
|
||||
extraLanguageFeatures: MutableMap<LanguageFeature, LanguageFeature.State>,
|
||||
commandLineArguments: K2JVMCompilerArguments
|
||||
) {
|
||||
if (commandLineArguments.strictJavaNullabilityAssertions) {
|
||||
extraLanguageFeatures[LanguageFeature.StrictJavaNullabilityAssertions] = LanguageFeature.State.ENABLED
|
||||
}
|
||||
|
||||
super.setupPlatformSpecificLanguageFeatureSettings(extraLanguageFeatures, commandLineArguments)
|
||||
}
|
||||
|
||||
private fun registerJavacIfNeeded(
|
||||
environment: KotlinCoreEnvironment,
|
||||
arguments: K2JVMCompilerArguments
|
||||
|
||||
@@ -66,5 +66,8 @@ class AnalysisFlag<out T> internal constructor(
|
||||
|
||||
@JvmStatic
|
||||
val useExperimental by Flag.ListOfStrings
|
||||
|
||||
@JvmStatic
|
||||
val explicitApiVersion by Flag.Boolean
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user