Skip to content

Commit a86db05

Browse files
committed
-Yscala-release support: checking if classes come from stdlib based on jar name; better documentation
1 parent 3f88de4 commit a86db05

File tree

7 files changed

+49
-8
lines changed

7 files changed

+49
-8
lines changed

compiler/src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ object Contexts {
493493
import math.Ordered.orderingToOrdered
494494
val latestRelease = ScalaRelease.latest
495495
val specifiedRelease = scalaRelease
496-
if ((specifiedRelease.majorVersion, specifiedRelease.minorVersion) < (latestRelease.majorVersion, latestRelease.minorVersion)) then
496+
if specifiedRelease < latestRelease then
497497
// This is needed to make -Yscala-release a no-op when set to the latest release for unstable versions of the compiler
498498
// (which might have the tasty format version numbers set to higher values before they're decreased during a release)
499499
TastyVersion.fromStableScalaRelease(specifiedRelease.majorVersion, specifiedRelease.minorVersion)

compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -969,9 +969,13 @@ class ClassfileParser(
969969
if !isTastyReadable then
970970
reportWrongTasty("its TASTy format cannot be read by the compiler", TastyVersion.compilerVersion)
971971
else
972-
val isTastyCompatible =
973-
fileTastyVersion.isCompatibleWith(ctx.tastyVersion) ||
974-
classRoot.symbol.showFullName.startsWith("scala.") // References to stdlib are considered safe because we check the values of @since annotations
972+
def isStdlibClass(cls: ClassDenotation): Boolean =
973+
ctx.platform.classPath.findClassFile(cls.fullName.mangledString) match {
974+
case Some(entry: ZipArchive#Entry) =>
975+
entry.underlyingSource.map(_.name.startsWith("scala3-library_3-")).getOrElse(false)
976+
case _ => false
977+
}
978+
val isTastyCompatible = fileTastyVersion.isCompatibleWith(ctx.tastyVersion) || isStdlibClass(classRoot)
975979
if !isTastyCompatible then
976980
reportWrongTasty(s"its TASTy format is not compatible with the one of the targeted Scala release (${ctx.scalaRelease.show})", ctx.tastyVersion)
977981

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
layout: doc-page
3+
title: "Binary Compatibility"
4+
---
5+
6+
Thanks to TASTy files, which are produced during compilation of Scala 3 sources, unlike Scala 2, Scala 3 is backward binary compatible between different minor versions (i.e. binary artifacts produced with Scala 3.x can be consumed by Scala 3.y programs as long as x <= y).
7+
There are however already some ongoing attempts to make Scala 3 forward binary compatible which means that, with some restrictions, it might be possible to compile Scala code with a newer version of the compiler and then use the produced binaries as dependencies for a project using an older compiler.
8+
9+
Scala 3.1.2-RC1 adds an experimental `-Yscala-release <release-version>` compiler flag which makes the compiler produce TASTy files that should be possible to use by all Scala 3 compilers in version `<release-version>` or newer (this flag was inspired by how `-release` works for specifying the target version of JDK). More specifically this flag enforces emitting TASTy files in an older format ensuring that:
10+
* the code contains no references to parts of the standard library which were added to the API after `<release-version>` and would crash at runtime when a program is executed with the older version of the standard library on the classpath
11+
* no dependency found on the classpath during compilation (except for the standard library itself) contains TASTy files produced by a compiler newer than `<release-version>` (otherwise they could potentially leak such disallowed references to the standard library)
12+
If any of the checks above is not fulfilled or for any other reason older TASTy cannot be emitted (e.g. the code uses some new language features which cannot be expressed the the older format) the entire compilation fails (with errors reported for each of such issues).
13+
14+
As this feature is experimental it does not have any special support in build tools yet (at least not in sbt 1.6.1 or lower).
15+
E.g. when a project gets compiled with Scala compiler `3.x1.y1` and `-Yscala-release 3.x2` option and then published using sbt
16+
then the standard library in version `3.x1.y1` gets added to the project's dependencies instead of `3.x2.y2`.
17+
When the dependencies are added to the classpath during compilation with Scala `3.x2.y2` the compiler will crash while trying to read TASTy files in the newer format.
18+
A currently known workaround is to modify the build definition of the dependent project by explicitly overriding the version of Scala standard library in dependencies, e.g.
19+
20+
```scala
21+
dependencyOverrides ++= Seq(
22+
scalaOrganization.value %% "scala3-library" % scalaVersion.value,
23+
scalaOrganization.value %% "scala3-library_sjs1" % scalaVersion.value // for Scala.js projects
24+
)
25+
```
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
layout: doc-page
3+
title: "Language Versions"
4+
---
5+
6+
Additional information on interoperability and migration between Scala 2 and 3 can be found [here](https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html).

docs/docs/reference/language-versions.md renamed to docs/docs/reference/language-versions/source-compatibility.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
---
22
layout: doc-page
3-
title: "Language Versions"
3+
title: "Source Compatibility"
44
movedTo: https://docs.scala-lang.org/scala3/reference/language-versions.html
55
---
66

7-
The default Scala language version currently supported by the Dotty compiler is [`3.0`](https://scala-lang.org/api/3.x/scala/runtime/stdLibPatches/language$$3/0$.html). There are also other language versions that can be specified instead:
7+
Scala 3 does NOT guarantee source compatibility between different minor language versions (e.g. some syntax valid in 3.x might get deprecated and then phased out in 3.y for y > x). There are also some syntax structures that were valid in Scala 2 but are not anymore in Scala 3. However the compiler provides a possibility to specify the desired version of syntax used in a particular file or globally for a run of the compiler to make migration between versions easier.
8+
9+
The default Scala language syntax version currently supported by the Dotty compiler is [`3.0`](https://scala-lang.org/api/3.x/scala/runtime/stdLibPatches/language$$3/0$.html). There are also other language versions that can be specified instead:
810

911
- [`3.0-migration`](https://scala-lang.org/api/3.x/scala/runtime/stdLibPatches/language$$3/0-migration$.html): Same as `3.0` but with a Scala 2 compatibility mode that helps moving Scala 2.13 sources over to Scala 3. In particular, it
1012

docs/sidebar.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,11 @@ sidebar:
119119
- page: docs/reference/experimental/named-typeargs-spec.md
120120
- page: docs/reference/experimental/numeric-literals.md
121121
- page: docs/reference/syntax.md
122-
- page: docs/reference/language-versions.md
122+
- title: Language Versions
123+
index: docs/reference/language-versions/language-versions.md
124+
subsection:
125+
- page: docs/reference/language-versions/source-compatibility.md
126+
- page: docs/reference/language-versions/binary-compatibility.md
123127
- title: Contributing
124128
subsection:
125129
- page: docs/contributing/contribute-knowledge.md

sbt-community-build/src/dotty/communitybuild/sbtplugin/CommunityBuildPlugin.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ object CommunityBuildPlugin extends AutoPlugin {
5353
val forwardCompatFilter: ModuleID => Boolean = if (isForwardCompatProject.value) (_.revision.contains("-forward-compat")) else (!_.revision.contains("-forward-compat"))
5454
val stdlibOverrides = Seq(
5555
scalaOrganization.value %% "scala3-library" % scalaVersion.value,
56-
scalaOrganization.value %% "scala3-library_sjs1" % scalaVersion.value,
56+
scalaOrganization.value %% "scala3-library_sjs1" % scalaVersion.value
5757
)
5858
CommunityBuildDependencies.allOverrides(sLog.value).filter(forwardCompatFilter) ++ stdlibOverrides
5959
} else Nil

0 commit comments

Comments
 (0)