diff --git a/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala b/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala index 5fbe7212a674..a47e2d348c8d 100644 --- a/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala +++ b/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala @@ -102,10 +102,17 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath { ClassPathEntries(distinctPackages, distinctClassesAndSources) } - /** - * Returns only one entry for each name. If there's both a source and a class entry, it - * creates an entry containing both of them. If there would be more than one class or source - * entries for the same class it always would use the first entry of each type found on a classpath. + /** Returns only one entry for each name. + * + * If there's both a source and a class entry, it + * creates an entry containing both of them. If there would be more than one class or source + * entries for the same class it always would use the first entry of each type found on a classpath. + * + * A class entry with a TASTy file will be chosen over one with a class file. Usually the class entries + * are already TASTy files when loading Scala 3 classes because the other classpath loaders load the TASTy. + * There is one exception if we load the Scala 2 library as it has one JAR containing the class files and one + * JAR containing the TASTy files. As classpath orders are not guaranteed to be deterministic we might end up + * having the TASTy in a later classpath entry. */ private def mergeClassesAndSources(entries: scala.collection.Seq[ClassRepresentation]): Seq[ClassRepresentation] = { // based on the implementation from MergedClassPath @@ -120,8 +127,15 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath { val index = indices(name) val existing = mergedEntries(index) - if (existing.binary.isEmpty && entry.binary.isDefined) - mergedEntries(index) = ClassAndSourceFilesEntry(entry.binary.get, existing.source.get) + (existing.binary, entry.binary) match + case (None, Some(entryBinary)) => + mergedEntries(index) = ClassAndSourceFilesEntry(entryBinary, existing.source.get) + case (Some(_), Some(entryBinary)) if entry.fileName.endsWith(".tasty") && existing.fileName.endsWith(".class") => + mergedEntries(index) = existing.source match + case Some(source) => ClassAndSourceFilesEntry(entryBinary, source) + case None => entry + case _ => + if (existing.source.isEmpty && entry.source.isDefined) mergedEntries(index) = ClassAndSourceFilesEntry(existing.binary.get, entry.source.get) } diff --git a/project/Build.scala b/project/Build.scala index 0e3f725bb180..6161e072faf0 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -782,24 +782,21 @@ object Build { else if (debugFromTasty) "dotty.tools.dotc.fromtasty.Debug" else "dotty.tools.dotc.Main" - val scala2LibraryTasty = scala2Library.value match { - case Scala2LibraryJar => Seq.empty + var extraClasspath = Seq(scalaLib, dottyLib) + + scala2Library.value match { + case Scala2LibraryJar => case Scala2LibraryTasty => jars.get("scala2-library-tasty") match { - case Some(jar) => Seq(jar) - case None => - log.warn("Scala2LibraryTasty is ignored on non-bootstrapped compiler") - Seq.empty - } + case Some(jar) => extraClasspath :+= jar + case None => log.warn("Scala2LibraryTasty is ignored on non-bootstrapped compiler") + }; case Scala2LibraryCCTasty => jars.get("scala2-library-cc-tasty") match { - case Some(jar) => Seq(jar) - case None => - log.warn("Scala2LibraryCCTasty is ignored on non-bootstrapped compiler") - Seq.empty + case Some(jar) => extraClasspath :+= jar + case None => log.warn("Scala2LibraryCCTasty is ignored on non-bootstrapped compiler") } } - var extraClasspath = scala2LibraryTasty ++ Seq(scalaLib, dottyLib) if (decompile && !args.contains("-classpath")) extraClasspath ++= Seq(".") @@ -1267,13 +1264,6 @@ object Build { Compile / compile / fullClasspath ~= { _.filterNot(file => file.data.getName == s"scala-library-$stdlibBootstrappedVersion.jar") }, - Compile / compile / dependencyClasspath := { - // make sure that the scala2-library (tasty of `scala2-library-tasty`) is listed before the scala-library (classfiles) - val (bootstrappedLib, otherLibs) = - (Compile / compile / dependencyClasspath).value - .partition(_.data.getName == s"scala2-library-${dottyVersion}.jar") - bootstrappedLib ++ otherLibs - }, ) lazy val `scala3-sbt-bridge` = project.in(file("sbt-bridge/src")). @@ -1920,6 +1910,7 @@ object Build { (`scala3-interfaces` / publishLocalBin), (`scala3-compiler-bootstrapped` / publishLocalBin), (`scala3-library-bootstrapped` / publishLocalBin), + (`scala2-library-tasty` / publishLocal), (`scala3-library-bootstrappedJS` / publishLocalBin), (`tasty-core-bootstrapped` / publishLocalBin), (`scala3-staging` / publishLocalBin), diff --git a/sbt-test/sbt-dotty/scala2-library-tasty/build.sbt b/sbt-test/sbt-dotty/scala2-library-tasty/build.sbt new file mode 100644 index 000000000000..ce95be79470f --- /dev/null +++ b/sbt-test/sbt-dotty/scala2-library-tasty/build.sbt @@ -0,0 +1,4 @@ +scalaVersion := sys.props("plugin.scalaVersion") + +libraryDependencies += "org.scala-lang" %% "scala2-library-tasty" % scalaVersion.value +scalacOptions += "-Yscala2-unpickler:never" // check that we do not load symbol from the Scala 2 library classfiles (use TASTy) diff --git a/sbt-test/sbt-dotty/scala2-library-tasty/src/main/scala/hello/Hello.scala b/sbt-test/sbt-dotty/scala2-library-tasty/src/main/scala/hello/Hello.scala new file mode 100644 index 000000000000..87277631f69b --- /dev/null +++ b/sbt-test/sbt-dotty/scala2-library-tasty/src/main/scala/hello/Hello.scala @@ -0,0 +1,4 @@ +package hello + +@main def hello: Unit = + println(Some("Hello world!")) // load Some form the Scala 2 library TASTy diff --git a/sbt-test/sbt-dotty/scala2-library-tasty/test b/sbt-test/sbt-dotty/scala2-library-tasty/test new file mode 100644 index 000000000000..62ea636c177f --- /dev/null +++ b/sbt-test/sbt-dotty/scala2-library-tasty/test @@ -0,0 +1 @@ +> run