From 3f6aeb6dcac3cb9a23506b61df9e07e84ec220bb Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 9 Feb 2018 18:15:35 +0100 Subject: [PATCH] Refactor API version inference/checking code The behavior is not changed in this commit --- .../JvmRuntimeVersionsConsistencyChecker.kt | 63 +++++++++---------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/JvmRuntimeVersionsConsistencyChecker.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/JvmRuntimeVersionsConsistencyChecker.kt index 2bf3720100f..795aff41bf7 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/JvmRuntimeVersionsConsistencyChecker.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/JvmRuntimeVersionsConsistencyChecker.kt @@ -102,33 +102,38 @@ object JvmRuntimeVersionsConsistencyChecker { if (runtimeJarsInfo.jars.isEmpty()) return val languageVersionSettings = configuration.languageVersionSettings - val apiVersion = languageVersionSettings.apiVersion.version + val currentApi = languageVersionSettings.apiVersion - val consistency = checkCompilerClasspathConsistency(messageCollector, apiVersion, runtimeJarsInfo) + val consistency = checkCompilerClasspathConsistency(messageCollector, currentApi.version, runtimeJarsInfo) if (consistency is ClasspathConsistency.InconsistentWithApiVersion) { val actualRuntimeVersion = consistency.actualRuntimeVersion messageCollector.issue( null, "Runtime JAR files in the classpath have the version $actualRuntimeVersion, " + - "which is older than the API version $apiVersion. " + - "Consider using the runtime of version $apiVersion, or pass '-api-version $actualRuntimeVersion' explicitly to " + - "restrict the available APIs to the runtime of version $actualRuntimeVersion. " + + "which is older than the API version ${currentApi.version}. " + + "Consider using the runtime of version ${currentApi.version}, or pass '-api-version $actualRuntimeVersion' " + + "explicitly to restrict the available APIs to the runtime of version $actualRuntimeVersion. " + "You can also pass '-language-version $actualRuntimeVersion' instead, which will restrict " + "not only the APIs to the specified version, but also the language features" ) - val actualApi = ApiVersion.parse(actualRuntimeVersion.toString()) - if (actualApi != null) { - val inferredApiVersion = - if (configuration.getBoolean(CLIConfigurationKeys.IS_API_VERSION_EXPLICIT)) - languageVersionSettings.apiVersion - else - // "minOf" is needed in case when API version was inferred from language version and it's older than actualApi. - // For example, in "kotlinc-1.2 -language-version 1.0 -cp kotlin-runtime-1.1.jar" we should still infer API = 1.0 - minOf(languageVersionSettings.apiVersion, actualApi) + for (jar in consistency.incompatibleJars) { + messageCollector.issue( + jar.file, + "Runtime JAR file has version ${jar.version} which is older than required for API version ${currentApi.version}" + ) + } + 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) { + // 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 + // "kotlinc-1.2 -language-version 1.0 -cp kotlin-runtime-1.1.jar" we should still infer API = 1.0 val newSettings = object : LanguageVersionSettings by languageVersionSettings { - override val apiVersion: ApiVersion get() = inferredApiVersion + override val apiVersion: ApiVersion get() = actualApi } messageCollector.issue(null, "Old runtime has been found in the classpath. " + @@ -137,9 +142,6 @@ object JvmRuntimeVersionsConsistencyChecker { configuration.languageVersionSettings = newSettings } - else { - messageCollector.issue(null, "Could not parse runtime JAR version: $actualRuntimeVersion") - } } else if (consistency != ClasspathConsistency.Consistent) { messageCollector.issue( @@ -165,7 +167,10 @@ object JvmRuntimeVersionsConsistencyChecker { private sealed class ClasspathConsistency { object Consistent : ClasspathConsistency() - class InconsistentWithApiVersion(val actualRuntimeVersion: MavenComparableVersion) : ClasspathConsistency() + class InconsistentWithApiVersion( + val actualRuntimeVersion: MavenComparableVersion, + val incompatibleJars: List + ) : ClasspathConsistency() object InconsistentWithCompilerVersion : ClasspathConsistency() object InconsistentBecauseOfRuntimesWithDifferentVersions : ClasspathConsistency() } @@ -189,9 +194,10 @@ object JvmRuntimeVersionsConsistencyChecker { val runtimeVersion = checkMatchingVersionsAndGetRuntimeVersion(messageCollector, jars) ?: return ClasspathConsistency.InconsistentBecauseOfRuntimesWithDifferentVersions - if (jars.map { - checkCompatibleWithApiVersion(messageCollector, it, apiVersion) - }.any { it }) return ClasspathConsistency.InconsistentWithApiVersion(runtimeVersion) + val jarsIncompatibleWithApiVersion = jars.filter { it.version < apiVersion } + if (jarsIncompatibleWithApiVersion.isNotEmpty()) { + return ClasspathConsistency.InconsistentWithApiVersion(runtimeVersion, jarsIncompatibleWithApiVersion) + } return ClasspathConsistency.Consistent } @@ -208,19 +214,6 @@ object JvmRuntimeVersionsConsistencyChecker { return false } - private fun checkCompatibleWithApiVersion( - messageCollector: MessageCollector, jar: KotlinLibraryFile, apiVersion: MavenComparableVersion - ): Boolean { - if (jar.version < apiVersion) { - messageCollector.issue( - jar.file, - "Runtime JAR file has version ${jar.version} which is older than required for API version $apiVersion" - ) - return true - } - return false - } - // Returns the version if it's the same across all jars, or null if versions of some jars differ. private fun checkMatchingVersionsAndGetRuntimeVersion( messageCollector: MessageCollector,