Refactor language feature settings processing for exposing it outside of the CLI compiler

This commit is contained in:
Ilya Chernikov
2018-02-08 18:47:47 +01:00
parent 58edab37c1
commit 643e81f0ae
7 changed files with 96 additions and 133 deletions
@@ -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()
}
@@ -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 =
@@ -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