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 f8b20389668..c150e4626d7 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/JvmRuntimeVersionsConsistencyChecker.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/JvmRuntimeVersionsConsistencyChecker.kt @@ -125,15 +125,19 @@ object JvmRuntimeVersionsConsistencyChecker { val consistency = checkCompilerClasspathConsistency(messageCollector, apiVersion, runtimeJarsInfo) if (consistency != ClasspathConsistency.Consistent) { - val extraHint = - if (consistency == ClasspathConsistency.InconsistentWithApiVersion) - "Remove them from the classpath or pass the correct '-api-version' explicitly. " + - "You can also pass the '-language-version' instead, which will restrict not only the APIs " + - "to the specified version, but also the language features. " + - "Alternatively, you can use '-Xskip-runtime-version-check' to suppress this error" - else - "Remove them from the classpath or use '-Xskip-runtime-version-check' to suppress errors" - messageCollector.issue(null, "Some runtime JAR files in the classpath have an incompatible version. $extraHint") + val message = when (consistency) { + is ClasspathConsistency.InconsistentWithApiVersion -> + "Runtime JAR files in the classpath have the version ${consistency.actualRuntimeVersion}, " + + "which is older than the API version $apiVersion. " + + "Remove them from the classpath or pass '-api-version ${consistency.actualRuntimeVersion}' explicitly. " + + "You can also pass '-language-version ${consistency.actualRuntimeVersion}' instead, which will restrict " + + "not only the APIs to the specified version, but also the language features. " + + "Alternatively, you can use '-Xskip-runtime-version-check' to suppress this error" + else -> + "Some runtime JAR files in the classpath have an incompatible version. " + + "Remove them from the classpath or use '-Xskip-runtime-version-check' to suppress errors" + } + messageCollector.issue(null, message) } val librariesWithBundled = runtimeJarsInfo.otherLibrariesWithBundledRuntime @@ -158,7 +162,7 @@ object JvmRuntimeVersionsConsistencyChecker { private sealed class ClasspathConsistency { object Consistent : ClasspathConsistency() - object InconsistentWithApiVersion : ClasspathConsistency() + class InconsistentWithApiVersion(val actualRuntimeVersion: MavenComparableVersion) : ClasspathConsistency() object InconsistentWithCompilerVersion : ClasspathConsistency() object InconsistentBecauseOfRuntimesWithDifferentVersions : ClasspathConsistency() } @@ -176,13 +180,15 @@ object JvmRuntimeVersionsConsistencyChecker { checkNotNewerThanCompiler(messageCollector, it) }.any { it }) return ClasspathConsistency.InconsistentWithCompilerVersion - if (checkMatchingVersions(messageCollector, runtimeJarsInfo)) { - return ClasspathConsistency.InconsistentBecauseOfRuntimesWithDifferentVersions - } + val jars = runtimeJarsInfo.jars + if (jars.isEmpty()) return ClasspathConsistency.Consistent - if (runtimeJarsInfo.jars.map { + val runtimeVersion = checkMatchingVersionsAndGetRuntimeVersion(messageCollector, jars) + ?: return ClasspathConsistency.InconsistentBecauseOfRuntimesWithDifferentVersions + + if (jars.map { checkCompatibleWithApiVersion(messageCollector, it, apiVersion) - }.any { it }) return ClasspathConsistency.InconsistentWithApiVersion + }.any { it }) return ClasspathConsistency.InconsistentWithApiVersion(runtimeVersion) return ClasspathConsistency.Consistent } @@ -205,21 +211,26 @@ object JvmRuntimeVersionsConsistencyChecker { return false } - private fun checkMatchingVersions(messageCollector: MessageCollector, runtimeJarsInfo: RuntimeJarsInfo): Boolean { - val oldestJar = runtimeJarsInfo.jars.minBy { it.version } ?: return false - val newestJar = runtimeJarsInfo.jars.maxBy { it.version } ?: 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, + jars: List + ): MavenComparableVersion? { + assert(jars.isNotEmpty()) { "'jars' must not be empty" } + val oldestVersion = jars.minBy { it.version }!!.version + val newestVersion = jars.maxBy { it.version }!!.version - if (oldestJar.version != newestJar.version) { - messageCollector.issue(null, buildString { - appendln("Runtime JAR files in the classpath must have the same version. These files were found in the classpath:") - for (jar in runtimeJarsInfo.jars) { - appendln(" ${jar.file.path} (version ${jar.version})") - } - }.trimEnd()) - return true - } + // If the oldest version is the same as the newest version, then all jars have the same version + if (oldestVersion == newestVersion) return oldestVersion - return false + messageCollector.issue(null, buildString { + appendln("Runtime JAR files in the classpath must have the same version. These files were found in the classpath:") + for (jar in jars) { + appendln(" ${jar.file.path} (version ${jar.version})") + } + }.trimEnd()) + + return null } private fun MessageCollector.issue(file: VirtualFile?, message: String, severity: CompilerMessageSeverity = VERSION_ISSUE_SEVERITY) {