From 73f872172fdb508de3c1185d9c0abd2665f6574d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 24 Oct 2016 17:48:07 +0300 Subject: [PATCH] Add multi-platform projects as experimental language feature --- .../arguments/CommonCompilerArguments.java | 3 + .../kotlin/cli/common/CLICompiler.java | 64 +++++++++++-------- .../rendering/DefaultErrorMessages.java | 8 ++- compiler/testData/cli/js/jsExtraHelp.out | 1 + compiler/testData/cli/jvm/extraHelp.out | 1 + .../kotlin/config/LanguageVersionSettings.kt | 26 +++++--- 6 files changed, 67 insertions(+), 36 deletions(-) diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.java b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.java index ce6bf7889a5..6e3fb842e9b 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.java +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.java @@ -64,6 +64,9 @@ public abstract class CommonCompilerArguments { @ValueDescription("") public String[] pluginClasspaths; + @Argument(value = "Xmulti-platform", description = "Enable experimental language support for multi-platform projects") + public boolean multiPlatform; + @Argument(value = "P", description = "Pass an option to a plugin") @ValueDescription(PLUGIN_OPTION_FORMAT) public String[] pluginOptions; diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java index 0b6f5b24803..f4a8c7fa9c9 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java @@ -42,6 +42,7 @@ import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStat import org.jetbrains.kotlin.utils.StringsKt; import java.io.PrintStream; +import java.util.ArrayList; import java.util.List; import java.util.Properties; @@ -248,33 +249,46 @@ public abstract class CLICompiler { configuration.put(CLIConfigurationKeys.COMPILER_JAR_LOCATOR, locator); } - LanguageVersion languageVersion = parseVersion(configuration, arguments.languageVersion, "language"); - LanguageVersion apiVersion = parseVersion(configuration, arguments.apiVersion, "API"); - if (languageVersion != null || apiVersion != null) { - if (languageVersion == null) { - // If only "-api-version" is specified, language version is assumed to be the latest - languageVersion = LanguageVersion.LATEST; - } - if (apiVersion == null) { - // 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) - apiVersion = languageVersion; - } - - if (apiVersion.compareTo(languageVersion) > 0) { - configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report( - CompilerMessageSeverity.ERROR, - "-api-version (" + apiVersion.getVersionString() + ") cannot be greater than " + - "-language-version (" + languageVersion.getVersionString() + ")", - CompilerMessageLocation.NO_LOCATION - ); - } - - configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, - new LanguageVersionSettingsImpl(languageVersion, ApiVersion.createByLanguageVersion(apiVersion))); - } + setupLanguageVersionSettings(configuration, arguments); } + private static void setupLanguageVersionSettings( + @NotNull CompilerConfiguration configuration, @NotNull CommonCompilerArguments arguments + ) { + LanguageVersion languageVersion = parseVersion(configuration, arguments.languageVersion, "language"); + LanguageVersion apiVersion = parseVersion(configuration, arguments.apiVersion, "API"); + + if (languageVersion == null) { + // If only "-api-version" is specified, language version is assumed to be the latest + languageVersion = LanguageVersion.LATEST; + } + if (apiVersion == null) { + // 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) + apiVersion = languageVersion; + } + + if (apiVersion.compareTo(languageVersion) > 0) { + configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report( + CompilerMessageSeverity.ERROR, + "-api-version (" + apiVersion.getVersionString() + ") cannot be greater than " + + "-language-version (" + languageVersion.getVersionString() + ")", + CompilerMessageLocation.NO_LOCATION + ); + } + + List extraLanguageFeatures = new ArrayList(0); + if (arguments.multiPlatform) { + extraLanguageFeatures.add(LanguageFeature.MultiPlatformProjects); + } + + configuration.put( + CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, + new LanguageVersionSettingsImpl(languageVersion, ApiVersion.createByLanguageVersion(apiVersion), extraLanguageFeatures) + ); + } + + @Nullable private static LanguageVersion parseVersion( @NotNull CompilerConfiguration configuration, @Nullable String value, @NotNull String versionOf ) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 1a5a8c06e4f..1e8dbd2585f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import org.jetbrains.kotlin.config.LanguageFeature; +import org.jetbrains.kotlin.config.LanguageVersion; import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.DiagnosticFactory; import org.jetbrains.kotlin.diagnostics.Errors; @@ -517,11 +518,14 @@ public class DefaultErrorMessages { MAP.put(UNSAFE_IMPLICIT_INVOKE_CALL, "Reference has a nullable type ''{0}'', use explicit ''?.invoke()'' to make a function-like call instead", RENDER_TYPE); MAP.put(AMBIGUOUS_LABEL, "Ambiguous label"); MAP.put(UNSUPPORTED, "Unsupported [{0}]", STRING); - MAP.put(UNSUPPORTED_FEATURE, "The feature is only available since Kotlin {0}", new DiagnosticParameterRenderer() { + MAP.put(UNSUPPORTED_FEATURE, "The feature is {0}", new DiagnosticParameterRenderer() { @NotNull @Override public String render(LanguageFeature feature, @NotNull RenderingContext renderingContext) { - return feature.getSinceVersion().getVersionString() + ": " + feature.getPresentableText(); + LanguageVersion version = feature.getSinceVersion(); + return version != null + ? "only available since Kotlin " + version.getVersionString() + ": " + feature.getPresentableText() + : "experimental and should be turned on explicitly via a command line option or in IDE settings: " + feature.getPresentableText(); } }); MAP.put(EXCEPTION_FROM_ANALYZER, "Internal Error occurred while analyzing this expression:\n{0}", THROWABLE); diff --git a/compiler/testData/cli/js/jsExtraHelp.out b/compiler/testData/cli/js/jsExtraHelp.out index a0622d5f289..6033fa4a18d 100644 --- a/compiler/testData/cli/js/jsExtraHelp.out +++ b/compiler/testData/cli/js/jsExtraHelp.out @@ -3,6 +3,7 @@ where advanced options include: -Xno-inline Disable method inlining -Xrepeat Repeat compilation (for performance analysis) -Xplugin Load plugins from the given classpath + -Xmulti-platform Enable experimental language support for multi-platform projects Advanced options are non-standard and may be changed or removed without any notice. OK \ No newline at end of file diff --git a/compiler/testData/cli/jvm/extraHelp.out b/compiler/testData/cli/jvm/extraHelp.out index c7d3e63b1a3..4bf3faab216 100644 --- a/compiler/testData/cli/jvm/extraHelp.out +++ b/compiler/testData/cli/jvm/extraHelp.out @@ -16,6 +16,7 @@ where advanced options include: -Xno-inline Disable method inlining -Xrepeat Repeat compilation (for performance analysis) -Xplugin Load plugins from the given classpath + -Xmulti-platform Enable experimental language support for multi-platform projects Advanced options are non-standard and may be changed or removed without any notice. OK \ No newline at end of file diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 0784b47832a..ed315134ccf 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -16,13 +16,11 @@ package org.jetbrains.kotlin.config -import com.intellij.openapi.module.Module -import com.intellij.util.text.VersionComparatorUtil import org.jetbrains.kotlin.config.LanguageVersion.KOTLIN_1_1 import org.jetbrains.kotlin.utils.DescriptionAware -enum class LanguageFeature(val sinceVersion: LanguageVersion) { - // Note: names of these entries are also used in diagnostic tests +enum class LanguageFeature(val sinceVersion: LanguageVersion?) { + // Note: names of these entries are also used in diagnostic tests and in user-visible messages (see presentableText below) TypeAliases(KOTLIN_1_1), BoundCallableReferences(KOTLIN_1_1), LocalDelegatedProperties(KOTLIN_1_1), @@ -34,7 +32,10 @@ enum class LanguageFeature(val sinceVersion: LanguageVersion) { DestructuringLambdaParameters(KOTLIN_1_1), SingleUnderscoreForParameterName(KOTLIN_1_1), DslMarkersSupport(KOTLIN_1_1), - UnderscoresInNumericLiterals(KOTLIN_1_1) + UnderscoresInNumericLiterals(KOTLIN_1_1), + + // Experimental features + MultiPlatformProjects(null), ; val presentableText: String @@ -74,15 +75,22 @@ interface LanguageVersionSettings { val apiVersion: ApiVersion } -class LanguageVersionSettingsImpl( +class LanguageVersionSettingsImpl @JvmOverloads constructor( private val languageVersion: LanguageVersion, - override val apiVersion: ApiVersion + override val apiVersion: ApiVersion, + additionalFeatures: Collection = emptySet() ) : LanguageVersionSettings { + private val additionalFeatures = additionalFeatures.toSet() + override fun supportsFeature(feature: LanguageFeature): Boolean { - return languageVersion >= feature.sinceVersion + val since = feature.sinceVersion + return (since != null && languageVersion >= since) || feature in additionalFeatures } - override fun toString() = "Language = $languageVersion, API = $apiVersion" + override fun toString() = buildString { + append("Language = $languageVersion, API = $apiVersion") + additionalFeatures.forEach { feature -> append(" +$feature") } + } companion object { @JvmField