diff --git a/project/Build.scala b/project/Build.scala index f36171aabbcd..db3f149cbab6 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -93,11 +93,12 @@ object Build { /** Version of the Scala compiler used to build the artifacts. * Reference version should track the latest version pushed to Maven: - * - In main branch it should be the last RC version (using experimental TASTy required for non-bootstrapped tests) + * - In main branch it should be the last RC version * - In release branch it should be the last stable release - * 3.6.0-RC1 was released as 3.6.0 - it's having and experimental TASTy version + * + * Warning: Change of this variable needs to be consulted with `expectedTastyVersion` */ - val referenceVersion = "3.6.0" + val referenceVersion = "3.6.3-RC1" /** Version of the Scala compiler targeted in the current release cycle * Contains a version without RC/SNAPSHOT/NIGHTLY specific suffixes @@ -105,6 +106,8 @@ object Build { * * Should only be referred from `dottyVersion` or settings/tasks requiring simplified version string, * eg. `compatMode` or Windows native distribution version. + * + * Warning: Change of this variable might require updating `expectedTastyVersion` */ val developedVersion = "3.6.4" @@ -116,6 +119,25 @@ object Build { * During final, stable release is set exactly to `developedVersion`. */ val baseVersion = s"$developedVersion-RC1" + + /** The version of TASTY that should be emitted, checked in runtime test + * For defails on how TASTY version should be set see related discussions: + * - https://github.com/scala/scala3/issues/13447#issuecomment-912447107 + * - https://github.com/scala/scala3/issues/14306#issuecomment-1069333516 + * - https://github.com/scala/scala3/pull/19321 + * + * Simplified rules, given 3.$minor.$patch = $developedVersion + * - Major version is always 28 + * - TASTY minor version: + * - in main (NIGHTLY): {if $patch == 0 then $minor else ${minor + 1}} + * - in release branch is always equal to $minor + * - TASTY experimental version: + * - in main (NIGHTLY) is always experimental + * - in release candidate branch is experimental if {patch == 0} + * - in stable release is always non-experimetnal + */ + val expectedTastyVersion = "28.7-experimental-1" + checkReleasedTastyVersion() /** Final version of Scala compiler, controlled by environment variables. */ val dottyVersion = { @@ -149,9 +171,9 @@ object Build { * For a developedVersion `3.M.P` the mimaPreviousDottyVersion should be set to: * - `3.M.0` if `P > 0` * - `3.(M-1).0` if `P = 0` - * 3.6.1 is an exception from this rule - 3.6.0 was a broken release + * 3.6.2 is an exception from this rule - 3.6.0 was a broken release, 3.6.1 was hotfix (unstable) release */ - val mimaPreviousDottyVersion = "3.6.1" + val mimaPreviousDottyVersion = "3.6.2" /** LTS version against which we check binary compatibility. * @@ -2424,6 +2446,9 @@ object Build { settings(disableDocSetting). settings( versionScheme := Some("semver-spec"), + Test / envVars ++= Map( + "EXPECTED_TASTY_VERSION" -> expectedTastyVersion, + ), if (mode == Bootstrapped) Def.settings( commonMiMaSettings, mimaForwardIssueFilters := MiMaFilters.TastyCore.ForwardsBreakingChanges, @@ -2473,6 +2498,34 @@ object Build { case Bootstrapped => commonBootstrappedSettings }) } + + /* Tests TASTy version invariants during NIGHLY, RC or Stable releases */ + def checkReleasedTastyVersion(): Unit = { + lazy val (scalaMinor, scalaPatch, scalaIsRC) = baseVersion.split("\\.|-").take(4) match { + case Array("3", minor, patch) => (minor.toInt, patch.toInt, false) + case Array("3", minor, patch, _) => (minor.toInt, patch.toInt, true) + case other => sys.error(s"Invalid Scala base version string: $baseVersion") + } + lazy val (tastyMinor, tastyIsExperimental) = expectedTastyVersion.split("\\.|-").take(4) match { + case Array("28", minor) => (minor.toInt, false) + case Array("28", minor, "experimental", _) => (minor.toInt, true) + case other => sys.error(s"Invalid TASTy version string: $expectedTastyVersion") + } + + if(isNightly) { + assert(tastyIsExperimental, "TASTY needs to be experimental in nightly builds") + val expectedTastyMinor = if(scalaPatch == 0) scalaMinor else scalaMinor + 1 + assert(tastyMinor == expectedTastyMinor, "Invalid TASTy minor version") + } + + if(isRelease) { + assert(scalaMinor == tastyMinor, "Minor versions of TASTY vesion and Scala version should match in release builds") + if (scalaIsRC && scalaPatch == 0) + assert(tastyIsExperimental, "TASTy should be experimental when releasing a new minor version RC") + else + assert(!tastyIsExperimental, "Stable version cannot use experimental TASTY") + } + } } object ScaladocConfigs { diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index 8f5f9d57a8a5..8ff590fefec5 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -324,7 +324,7 @@ object TastyFormat { * compatibility, but remains backwards compatible, with all * preceding `MinorVersion`. */ - final val MinorVersion: Int = 6 + final val MinorVersion: Int = 7 /** Natural Number. The `ExperimentalVersion` allows for * experimentation with changes to TASTy without committing diff --git a/tasty/test/dotty/tools/tasty/BuildTastyVersionTest.scala b/tasty/test/dotty/tools/tasty/BuildTastyVersionTest.scala new file mode 100644 index 000000000000..d2e62e1f9eb0 --- /dev/null +++ b/tasty/test/dotty/tools/tasty/BuildTastyVersionTest.scala @@ -0,0 +1,26 @@ +package dotty.tools.tasty + +import org.junit.Assert._ +import org.junit.Test + +import TastyBuffer._ + +// Tests ensuring TASTY version emitted by compiler is matching expected TASTY version +class BuildTastyVersionTest { + + val CurrentTastyVersion = TastyVersion(TastyFormat.MajorVersion, TastyFormat.MinorVersion, TastyFormat.ExperimentalVersion) + + // Needs to be defined in build Test/envVars + val ExpectedTastyVersionEnvVar = "EXPECTED_TASTY_VERSION" + + @Test def testBuildTastyVersion(): Unit = { + val expectedVersion = sys.env.get(ExpectedTastyVersionEnvVar) + .getOrElse(fail(s"Env variable $ExpectedTastyVersionEnvVar not defined")) + .match { + case s"$major.$minor-experimental-$experimental" => TastyVersion(major.toInt, minor.toInt, experimental.toInt) + case s"$major.$minor" if minor.forall(_.isDigit) => TastyVersion(major.toInt, minor.toInt, 0) + case other => fail(s"Invalid TASTY version string: $other") + } + assertEquals(CurrentTastyVersion, expectedVersion) + } +}