diff --git a/build.sc b/build.sc index 811d015c4c..1ea08965f2 100644 --- a/build.sc +++ b/build.sc @@ -489,6 +489,8 @@ trait Core extends ScalaCliCrossSbtModule | def defaultScalaVersion = "${Scala.defaultUser}" | def defaultScala212Version = "${Scala.scala212}" | def defaultScala213Version = "${Scala.scala213}" + | def scala3NextRcVersion = "${Scala.scala3NextRc}" + | def scala3NextPrefix = "${Scala.scala3NextPrefix}" | def scala3LtsPrefix = "${Scala.scala3LtsPrefix}" | | def workspaceDirName = "$workspaceDirName" diff --git a/modules/build/src/test/scala/scala/build/tests/BuildOptionsTests.scala b/modules/build/src/test/scala/scala/build/tests/BuildOptionsTests.scala index f7637d869f..c957b24544 100644 --- a/modules/build/src/test/scala/scala/build/tests/BuildOptionsTests.scala +++ b/modules/build/src/test/scala/scala/build/tests/BuildOptionsTests.scala @@ -17,6 +17,7 @@ import scala.build.internal.Regexes.scala2NightlyRegex import scala.build.options.{ BuildOptions, BuildRequirements, + ClassPathOptions, InternalOptions, MaybeScalaVersion, ScalaOptions, @@ -318,34 +319,61 @@ class BuildOptionsTests extends TestUtil.ScalaCliBuildSuite { expect(scalaParams == expectedScalaParams) } - for { - (prefix, defaultMatchingVersion) <- Seq( - "2.12" -> defaultScala212Version, - "2.13" -> defaultScala213Version, - "3" -> defaultScalaVersion - ) - } { - val options = BuildOptions( - scalaOptions = ScalaOptions( - scalaVersion = Some(prefix).map(MaybeScalaVersion(_)) - ), - internal = InternalOptions( - cache = Some(FileCache().withTtl(0.seconds)) + { + val cache = FileCache().withTtl(0.seconds) + val repositories = BuildOptions( + internal = InternalOptions(cache = Some(cache)), + classPathOptions = + ClassPathOptions(extraRepositories = Seq(coursier.Repositories.scalaIntegration.root)) + ).finalRepositories.orThrow + val allScalaVersions = ScalaVersionUtil.allMatchingVersions(None, cache, repositories) + for { + (prefix, defaultMatchingVersion, predefinedDefaultScalaVersion) <- { + val scala2Nightlies = allScalaVersions.filter(ScalaVersionUtil.isScala2Nightly) + val latest212Nightly = scala2Nightlies.filter(_.startsWith("2.12")).maxBy(Version(_)) + val latest213Nightly = scala2Nightlies.filter(_.startsWith("2.13")).maxBy(Version(_)) + val latestScala3NextNightly = + allScalaVersions + .filter(ScalaVersionUtil.isScala3Nightly) + .filter(_.startsWith(scala3NextPrefix)) + .maxBy(Version(_)) + Seq( + ("2.12", defaultScala212Version, None), + ("2.12", defaultScala212Version, Some(latest212Nightly)), + ("2.13", defaultScala213Version, None), + ("2.13", defaultScala213Version, Some(latest213Nightly)), + ("3", defaultScalaVersion, None), + (scala3NextPrefix, defaultScalaVersion, None), + (scala3NextPrefix, defaultScalaVersion, Some(latestScala3NextNightly)) + ) + } + options = BuildOptions( + scalaOptions = ScalaOptions( + scalaVersion = Some(prefix).map(MaybeScalaVersion(_)), + defaultScalaVersion = predefinedDefaultScalaVersion + ), + internal = InternalOptions( + cache = Some(cache) + ), + classPathOptions = ClassPathOptions( + extraRepositories = Seq(coursier.Repositories.scalaIntegration.root) + ) ) - ) - - val latestMatchingVersion = ScalaVersionUtil - .allMatchingVersions(None, options.finalCache, options.finalRepositories.orThrow) - .filter(ScalaVersionUtil.isStable) - .filter(_.startsWith(prefix)) - .maxBy(Version(_)) - - test( - s"-S $prefix should chose the latest version ($latestMatchingVersion), not necessarily the default ($defaultMatchingVersion)" - ) { + latestMatchingVersion = allScalaVersions + .filter(ScalaVersionUtil.isStable) + .filter(_.startsWith(prefix)) + .maxBy(Version(_)) + expectedVersion = predefinedDefaultScalaVersion.getOrElse(defaultMatchingVersion) + expectedVersionDescription = + if expectedVersion == defaultMatchingVersion then "default" else "overridden default" + launcherDefaultVersionDescription = if expectedVersion == defaultMatchingVersion then "" + else s"or the launcher default ($defaultMatchingVersion)" + testDescription = + s"-S $prefix should choose the $expectedVersionDescription version ($expectedVersion), not necessarily the latest stable ($latestMatchingVersion) $launcherDefaultVersionDescription" + } test(testDescription) { val scalaParams = options.scalaParams.orThrow.getOrElse(???) - val expectedScalaParams = ScalaParameters(latestMatchingVersion) + val expectedScalaParams = ScalaParameters(expectedVersion) expect(scalaParams == expectedScalaParams, s"expected $expectedScalaParams, got $scalaParams") } diff --git a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala index 193c01331e..66181732c1 100644 --- a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala @@ -317,69 +317,82 @@ final case class BuildOptions( scalaOptions.defaultScalaVersion.getOrElse(Constants.defaultScalaVersion) ) - val svOpt: Option[String] = scalaOptions.scalaVersion match { - case Some(MaybeScalaVersion(None)) => - None - // Do not validate Scala version in offline mode - case Some(MaybeScalaVersion(Some(svInput))) if internal.offline.getOrElse(false) => - Some(svInput) - // Do not validate Scala version if it is a default one - case Some(MaybeScalaVersion(Some(svInput))) if defaultVersions.contains(svInput) => - Some(svInput) - case Some(MaybeScalaVersion(Some(svInput))) => - val sv = value { - svInput match { - case sv if ScalaVersionUtil.scala3Lts.contains(sv) => - ScalaVersionUtil.validateStable( - Constants.scala3LtsPrefix, - cache, - repositories - ) - case sv if ScalaVersionUtil.scala2Lts.contains(sv) => - Left(new ScalaVersionError( - s"Invalid Scala version: $sv. There is no official LTS version for Scala 2." - )) - case sv if sv == ScalaVersionUtil.scala3Nightly => - ScalaVersionUtil.GetNightly.scala3(cache) - case scala3NightlyNicknameRegex(threeSubBinaryNum) => - ScalaVersionUtil.GetNightly.scala3X( - threeSubBinaryNum, - cache - ) - case vs if ScalaVersionUtil.scala213Nightly.contains(vs) => - ScalaVersionUtil.GetNightly.scala2("2.13", cache) - case sv if sv == ScalaVersionUtil.scala212Nightly => - ScalaVersionUtil.GetNightly.scala2("2.12", cache) - case versionString if ScalaVersionUtil.isScala3Nightly(versionString) => - ScalaVersionUtil.CheckNightly.scala3( - versionString, - cache - ) - .map(_ => versionString) - case versionString if ScalaVersionUtil.isScala2Nightly(versionString) => - ScalaVersionUtil.CheckNightly.scala2( - versionString, - cache - ) - .map(_ => versionString) - case versionString if versionString.exists(_.isLetter) => - ScalaVersionUtil.validateNonStable( - versionString, - cache, - repositories - ) - case versionString => - ScalaVersionUtil.validateStable( - versionString, - cache, - repositories - ) + val svOpt: Option[String] = + scalaOptions.scalaVersion -> scalaOptions.defaultScalaVersion match { + case (Some(MaybeScalaVersion(None)), _) => + None + // Do not validate Scala version in offline mode + case (Some(MaybeScalaVersion(Some(svInput))), _) if internal.offline.getOrElse(false) => + Some(svInput) + // Do not validate Scala version if it is a default one + case (Some(MaybeScalaVersion(Some(svInput))), _) if defaultVersions.contains(svInput) => + Some(svInput) + case (Some(MaybeScalaVersion(Some(svInput))), Some(predefinedScalaVersion)) + if predefinedScalaVersion.startsWith(svInput) && + (svInput == "3" || svInput == Constants.scala3NextPrefix || + svInput == "2.13" || svInput == "2.12") => + Some(predefinedScalaVersion) + case (Some(MaybeScalaVersion(Some(svInput))), None) + if svInput == "3" || svInput == Constants.scala3NextPrefix => + Some(Constants.defaultScalaVersion) + case (Some(MaybeScalaVersion(Some(svInput))), None) if svInput == "2.13" => + Some(Constants.defaultScala213Version) + case (Some(MaybeScalaVersion(Some(svInput))), None) if svInput == "2.12" => + Some(Constants.defaultScala212Version) + case (Some(MaybeScalaVersion(Some(svInput))), _) => + val sv = value { + svInput match { + case sv if ScalaVersionUtil.scala3Lts.contains(sv) => + ScalaVersionUtil.validateStable( + Constants.scala3LtsPrefix, + cache, + repositories + ) + case sv if ScalaVersionUtil.scala2Lts.contains(sv) => + Left(new ScalaVersionError( + s"Invalid Scala version: $sv. There is no official LTS version for Scala 2." + )) + case sv if sv == ScalaVersionUtil.scala3Nightly => + ScalaVersionUtil.GetNightly.scala3(cache) + case scala3NightlyNicknameRegex(threeSubBinaryNum) => + ScalaVersionUtil.GetNightly.scala3X( + threeSubBinaryNum, + cache + ) + case vs if ScalaVersionUtil.scala213Nightly.contains(vs) => + ScalaVersionUtil.GetNightly.scala2("2.13", cache) + case sv if sv == ScalaVersionUtil.scala212Nightly => + ScalaVersionUtil.GetNightly.scala2("2.12", cache) + case versionString if ScalaVersionUtil.isScala3Nightly(versionString) => + ScalaVersionUtil.CheckNightly.scala3( + versionString, + cache + ) + .map(_ => versionString) + case versionString if ScalaVersionUtil.isScala2Nightly(versionString) => + ScalaVersionUtil.CheckNightly.scala2( + versionString, + cache + ) + .map(_ => versionString) + case versionString if versionString.exists(_.isLetter) => + ScalaVersionUtil.validateNonStable( + versionString, + cache, + repositories + ) + case versionString => + ScalaVersionUtil.validateStable( + versionString, + cache, + repositories + ) + } } - } - Some(sv) - - case None => Some(scalaOptions.defaultScalaVersion.getOrElse(Constants.defaultScalaVersion)) - } + Some(sv) + case (None, Some(predefinedScalaVersion)) => Some(predefinedScalaVersion) + case _ => Some(Constants.defaultScalaVersion) + } svOpt match { case Some(scalaVersion) => diff --git a/project/deps.sc b/project/deps.sc index 3c211e619d..b8ed1546cf 100644 --- a/project/deps.sc +++ b/project/deps.sc @@ -7,8 +7,9 @@ object Scala { def scala213 = "2.13.15" def runnerScala3 = "3.0.2" // the newest version that is compatible with all Scala 3.x versions def scala3LtsPrefix = "3.3" // used for the LTS version tags - def scala3Lts = s"$scala3LtsPrefix.4" // the LTS version currently used in the build - def scala3Next = "3.5.2" // the newest/next version of Scala + def scala3Lts = s"$scala3LtsPrefix.4" // the LTS version currently used in the build + def scala3NextPrefix = "3.5" + def scala3Next = s"$scala3NextPrefix.2" // the newest/next version of Scala def scala3NextAnnounced = scala3Next // the newest/next version of Scala that's been announced def scala3NextRc = "3.6.1" // the latest RC version of Scala Next