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
|
package org.jetbrains.kotlin.cli.common.arguments
|
||||||
|
|
||||||
import com.intellij.util.xmlb.annotations.Transient
|
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.cli.common.messages.MessageCollector
|
||||||
import org.jetbrains.kotlin.config.AnalysisFlag
|
import org.jetbrains.kotlin.config.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
@@ -164,9 +165,89 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
|
|||||||
put(AnalysisFlag.allowKotlinPackage, allowKotlinPackage)
|
put(AnalysisFlag.allowKotlinPackage, allowKotlinPackage)
|
||||||
put(AnalysisFlag.experimental, experimental?.toList().orEmpty())
|
put(AnalysisFlag.experimental, experimental?.toList().orEmpty())
|
||||||
put(AnalysisFlag.useExperimental, useExperimental?.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!
|
// Used only for serialize and deserialize settings. Don't use in other places!
|
||||||
class DummyImpl : CommonCompilerArguments()
|
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.AnalysisFlag
|
||||||
import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode
|
import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode
|
||||||
import org.jetbrains.kotlin.config.JvmTarget
|
import org.jetbrains.kotlin.config.JvmTarget
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
|
||||||
class K2JVMCompilerArguments : CommonCompilerArguments() {
|
class K2JVMCompilerArguments : CommonCompilerArguments() {
|
||||||
companion object {
|
companion object {
|
||||||
@@ -235,4 +236,12 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
|||||||
)
|
)
|
||||||
return result
|
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.File;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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) {
|
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);
|
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()) {
|
CommonConfigurationKeysKt.setLanguageVersionSettings(configuration, arguments.configureLanguageVersionSettings(collector));
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String kotlinHomeEnvVar = System.getenv(KOTLIN_HOME_ENV_VAR);
|
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;
|
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(
|
protected abstract void setupPlatformSpecificArgumentsAndServices(
|
||||||
@NotNull CompilerConfiguration configuration, @NotNull A arguments, @NotNull Services services
|
@NotNull CompilerConfiguration configuration, @NotNull A arguments, @NotNull Services services
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ public class CLIConfigurationKeys {
|
|||||||
CompilerConfigurationKey.create("allow kotlin package");
|
CompilerConfigurationKey.create("allow kotlin package");
|
||||||
public static final CompilerConfigurationKey<Boolean> REPORT_PERF =
|
public static final CompilerConfigurationKey<Boolean> REPORT_PERF =
|
||||||
CompilerConfigurationKey.create("report performance information");
|
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)
|
// Used in Eclipse plugin (see KotlinCLICompiler)
|
||||||
public static final CompilerConfigurationKey<String> INTELLIJ_PLUGIN_ROOT =
|
public static final CompilerConfigurationKey<String> INTELLIJ_PLUGIN_ROOT =
|
||||||
|
|||||||
+1
-1
@@ -129,7 +129,7 @@ object JvmRuntimeVersionsConsistencyChecker {
|
|||||||
val actualApi = ApiVersion.parse(actualRuntimeVersion.toString())
|
val actualApi = ApiVersion.parse(actualRuntimeVersion.toString())
|
||||||
if (actualApi == null) {
|
if (actualApi == null) {
|
||||||
messageCollector.issue(null, "Could not parse runtime JAR version: $actualRuntimeVersion")
|
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),
|
// 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.
|
// we infer API = the version of that stdlib.
|
||||||
// Note that "no explicit -api-version" requirement is necessary because for example, in
|
// 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(
|
private fun registerJavacIfNeeded(
|
||||||
environment: KotlinCoreEnvironment,
|
environment: KotlinCoreEnvironment,
|
||||||
arguments: K2JVMCompilerArguments
|
arguments: K2JVMCompilerArguments
|
||||||
|
|||||||
@@ -66,5 +66,8 @@ class AnalysisFlag<out T> internal constructor(
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
val useExperimental by Flag.ListOfStrings
|
val useExperimental by Flag.ListOfStrings
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
val explicitApiVersion by Flag.Boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user