|
| 1 | +package scala.build.internal |
| 2 | + |
| 3 | +/** Scala version ↔ JDK compatibility ranges. |
| 4 | + * |
| 5 | + * Sourced from https://docs.scala-lang.org/overviews/jdk-compatibility/overview.html |
| 6 | + * |
| 7 | + * Non-stable versions (RC, nightly, custom suffixes) are normalised by stripping everything from |
| 8 | + * the first `-` onward (e.g. `3.7.4-RC1` → `3.7.4`). |
| 9 | + * |
| 10 | + * @param maxRecommendedJdk |
| 11 | + * highest JDK version Scala is tested with for this line; warn when a newer JDK is used. For |
| 12 | + * Scala 3.8+, this tracks the latest released JDK and should be bumped when new JDKs ship. |
| 13 | + */ |
| 14 | +final case class ScalaJdkCompat(minJdk: Int, maxRecommendedJdk: Int) |
| 15 | + |
| 16 | +object ScalaJdkCompat { |
| 17 | + |
| 18 | + def normalizeScalaVersion(scalaVersion: String): String = |
| 19 | + val dash = scalaVersion.indexOf('-') |
| 20 | + if dash < 0 then scalaVersion |
| 21 | + else scalaVersion.substring(0, dash) |
| 22 | + |
| 23 | + def forScalaVersion(scalaVersion: String): Option[ScalaJdkCompat] = |
| 24 | + parseVersion(normalizeScalaVersion(scalaVersion)).flatMap(compatFor.tupled) |
| 25 | + |
| 26 | + private def parseVersion(version: String): Option[(Int, Int, Int)] = |
| 27 | + val parts = version.split('.') |
| 28 | + if parts.length < 2 then None |
| 29 | + else |
| 30 | + for |
| 31 | + major <- parts(0).toIntOption |
| 32 | + minor <- parts(1).toIntOption |
| 33 | + patch = if parts.length >= 3 then parts(2).takeWhile(_.isDigit).toIntOption.getOrElse(0) |
| 34 | + else 0 |
| 35 | + yield (major, minor, patch) |
| 36 | + |
| 37 | + private def patchTable(table: Seq[(Int, Int)])(patch: Int): Int = |
| 38 | + table.reverseIterator.collectFirst { case (threshold, jdk) if patch >= threshold => jdk } |
| 39 | + .getOrElse(table.head._2) |
| 40 | + |
| 41 | + private val table_2_12 = Seq(0 -> 8, 4 -> 11, 15 -> 17, 18 -> 21, 21 -> 26) |
| 42 | + private val table_2_13 = Seq(0 -> 11, 6 -> 17, 11 -> 21, 17 -> 25, 18 -> 26) |
| 43 | + private val table_3_3 = Seq(0 -> 17, 1 -> 21, 6 -> 25, 8 -> 26) |
| 44 | + |
| 45 | + private def compatFor(major: Int, minor: Int, patch: Int): Option[ScalaJdkCompat] = |
| 46 | + (major, minor) match |
| 47 | + case (2, 12) => Some(ScalaJdkCompat(8, patchTable(table_2_12)(patch))) |
| 48 | + case (2, 13) => Some(ScalaJdkCompat(8, patchTable(table_2_13)(patch))) |
| 49 | + case (3, m) if m >= 8 => Some(ScalaJdkCompat(17, 26)) |
| 50 | + case (3, 7) => Some(ScalaJdkCompat(8, if patch >= 1 then 25 else 21)) |
| 51 | + case (3, m) if m >= 4 => Some(ScalaJdkCompat(8, 21)) |
| 52 | + case (3, 3) => Some(ScalaJdkCompat(8, patchTable(table_3_3)(patch))) |
| 53 | + case (3, _) => Some(ScalaJdkCompat(8, 17)) |
| 54 | + case _ => None |
| 55 | +} |
0 commit comments