Skip to content

Commit a0fd162

Browse files
committed
Prioritize TASTy files over classfiles on classpath aggregation
In most cases the TASTy file is chosen over the classfile in a classpath because they are packaged together. However, for the `scala-library` (Scala 2 compiled library) and `scala2-library-tasty` (Scala 3 compiled Scala 2 library) we have the classfiles in one jar and the TASTy files in another jar. Given that the classpaths order in guaranteed to be deterministic we might end up with the classfile being loaded first and the TASTy file second. The aggregator must be capable of choosing the TASTy file over the classfile in this case as well. This also implies that we can just add the `scala2-library-tasty` as a dependency in any project to use it. Note that this jar is not published yet.
1 parent b2ba6dc commit a0fd162

File tree

5 files changed

+38
-25
lines changed

5 files changed

+38
-25
lines changed

compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,17 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath {
102102
ClassPathEntries(distinctPackages, distinctClassesAndSources)
103103
}
104104

105-
/**
106-
* Returns only one entry for each name. If there's both a source and a class entry, it
107-
* creates an entry containing both of them. If there would be more than one class or source
108-
* entries for the same class it always would use the first entry of each type found on a classpath.
105+
/** Returns only one entry for each name.
106+
*
107+
* If there's both a source and a class entry, it
108+
* creates an entry containing both of them. If there would be more than one class or source
109+
* entries for the same class it always would use the first entry of each type found on a classpath.
110+
*
111+
* A class entry with a TASTy file will be chosen over one with a class file. Usually the class entries
112+
* are already TASTy files when loading Scala 3 classes because the other classpath loaders load the TASTy.
113+
* There is one exception if we load the Scala 2 library as it has one JAR containing the class files and one
114+
* JAR containing the TASTy files. As classpath orders are not guaranteed to be deterministic we might end up
115+
* having the TASTy in a later classpath entry.
109116
*/
110117
private def mergeClassesAndSources(entries: scala.collection.Seq[ClassRepresentation]): Seq[ClassRepresentation] = {
111118
// based on the implementation from MergedClassPath
@@ -120,8 +127,15 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath {
120127
val index = indices(name)
121128
val existing = mergedEntries(index)
122129

123-
if (existing.binary.isEmpty && entry.binary.isDefined)
124-
mergedEntries(index) = ClassAndSourceFilesEntry(entry.binary.get, existing.source.get)
130+
(existing.binary, entry.binary) match
131+
case (None, Some(entryBinary)) =>
132+
mergedEntries(index) = ClassAndSourceFilesEntry(entryBinary, existing.source.get)
133+
case (Some(_), Some(entryBinary)) if entry.fileName.endsWith(".tasty") && existing.fileName.endsWith(".class") =>
134+
mergedEntries(index) = existing.source match
135+
case Some(source) => ClassAndSourceFilesEntry(entryBinary, source)
136+
case None => entry
137+
case _ =>
138+
125139
if (existing.source.isEmpty && entry.source.isDefined)
126140
mergedEntries(index) = ClassAndSourceFilesEntry(existing.binary.get, entry.source.get)
127141
}

project/Build.scala

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -782,24 +782,21 @@ object Build {
782782
else if (debugFromTasty) "dotty.tools.dotc.fromtasty.Debug"
783783
else "dotty.tools.dotc.Main"
784784

785-
val scala2LibraryTasty = scala2Library.value match {
786-
case Scala2LibraryJar => Seq.empty
785+
var extraClasspath = Seq(scalaLib, dottyLib)
786+
787+
scala2Library.value match {
788+
case Scala2LibraryJar =>
787789
case Scala2LibraryTasty =>
788790
jars.get("scala2-library-tasty") match {
789-
case Some(jar) => Seq(jar)
790-
case None =>
791-
log.warn("Scala2LibraryTasty is ignored on non-bootstrapped compiler")
792-
Seq.empty
793-
}
791+
case Some(jar) => extraClasspath :+= jar
792+
case None => log.warn("Scala2LibraryTasty is ignored on non-bootstrapped compiler")
793+
};
794794
case Scala2LibraryCCTasty =>
795795
jars.get("scala2-library-cc-tasty") match {
796-
case Some(jar) => Seq(jar)
797-
case None =>
798-
log.warn("Scala2LibraryCCTasty is ignored on non-bootstrapped compiler")
799-
Seq.empty
796+
case Some(jar) => extraClasspath :+= jar
797+
case None => log.warn("Scala2LibraryCCTasty is ignored on non-bootstrapped compiler")
800798
}
801799
}
802-
var extraClasspath = scala2LibraryTasty ++ Seq(scalaLib, dottyLib)
803800

804801
if (decompile && !args.contains("-classpath"))
805802
extraClasspath ++= Seq(".")
@@ -1267,13 +1264,6 @@ object Build {
12671264
Compile / compile / fullClasspath ~= {
12681265
_.filterNot(file => file.data.getName == s"scala-library-$stdlibBootstrappedVersion.jar")
12691266
},
1270-
Compile / compile / dependencyClasspath := {
1271-
// make sure that the scala2-library (tasty of `scala2-library-tasty`) is listed before the scala-library (classfiles)
1272-
val (bootstrappedLib, otherLibs) =
1273-
(Compile / compile / dependencyClasspath).value
1274-
.partition(_.data.getName == s"scala2-library-${dottyVersion}.jar")
1275-
bootstrappedLib ++ otherLibs
1276-
},
12771267
)
12781268

12791269
lazy val `scala3-sbt-bridge` = project.in(file("sbt-bridge/src")).
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
scalaVersion := sys.props("plugin.scalaVersion")
2+
3+
libraryDependencies += "org.scala-lang" %% "scala2-library-tasty" % scalaVersion.value
4+
scalacOptions += "-Yscala2-unpickler:never" // check that we do not load symbol from the Scala 2 library classfiles (use TASTy)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package hello
2+
3+
@main def hello: Unit =
4+
println(Some("Hello world!")) // load Some form the Scala 2 library TASTy
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
> run

0 commit comments

Comments
 (0)