diff --git a/project/Build.scala b/project/Build.scala index 3e53990cfd56..03e58d98f3f3 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -20,6 +20,8 @@ import sbt.Package.ManifestAttributes import sbt.PublishBinPlugin.autoImport._ import dotty.tools.sbtplugin.RepublishPlugin import dotty.tools.sbtplugin.RepublishPlugin.autoImport._ +import dotty.tools.sbtplugin.ScalaLibraryPlugin + import sbt.plugins.SbtPlugin import sbt.ScriptedPlugin.autoImport._ import xerial.sbt.Sonatype.autoImport._ @@ -1207,6 +1209,7 @@ object Build { * This version of the library is not (yet) TASTy/binary compatible with the Scala 2 compiled library. */ lazy val `scala2-library-bootstrapped` = project.in(file("scala2-library-bootstrapped")). + enablePlugins(ScalaLibraryPlugin). withCommonSettings(Bootstrapped). dependsOn(dottyCompiler(Bootstrapped) % "provided; compile->runtime; test->test"). settings(scala2LibraryBootstrappedSettings). diff --git a/project/Scala2LibraryBootstrappedMiMaFilters.scala b/project/Scala2LibraryBootstrappedMiMaFilters.scala index 301e0075ba7f..dd0a885731b2 100644 --- a/project/Scala2LibraryBootstrappedMiMaFilters.scala +++ b/project/Scala2LibraryBootstrappedMiMaFilters.scala @@ -4,83 +4,44 @@ import com.typesafe.tools.mima.core._ object Scala2LibraryBootstrappedMiMaFilters { val BackwardsBreakingChanges: Map[String, Seq[ProblemFilter]] = Map( - Build.stdlibBootstrappedVersion -> { - Seq( - // Files that are not compiled in the bootstrapped library - ProblemFilters.exclude[MissingClassProblem]("scala.AnyVal"), - - // Scala language features - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.language."), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.language#experimental."), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.util.Properties."), - ProblemFilters.exclude[FinalClassProblem]("scala.language$experimental$"), - ProblemFilters.exclude[FinalClassProblem]("scala.languageFeature$*$"), - - // Issue: https://github.com/scala/scala3/issues/22495 - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.ArrayOps.scala$collection$ArrayOps$$elemTag$extension"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.ArrayOps.iterateUntilEmpty$extension"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.StringOps.isLineBreak$extension"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.StringOps.isLineBreak2$extension"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.StringOps.linesSeparated$extension"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.StringOps.escape$extension"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.StringOps.toBooleanImpl$extension"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.StringOps.unwrapArg$extension"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.StringOps.iterateUntilEmpty$extension"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuple2Zipped.coll1$extension"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuple2Zipped.coll2$extension"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuple3Zipped.coll1$extension"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuple3Zipped.coll2$extension"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuple3Zipped.coll3$extension"), - - // Companion module class - ProblemFilters.exclude[FinalClassProblem]("scala.*$"), - - // Scala 2 intrinsic macros - ProblemFilters.exclude[FinalMethodProblem]("scala.StringContext.s"), - - // Specialization? - ProblemFilters.exclude[MissingFieldProblem]("scala.Tuple1._1"), // field _1 in class scala.Tuple1 does not have a correspondent in current version - ProblemFilters.exclude[MissingFieldProblem]("scala.Tuple2._1"), // field _1 in class scala.Tuple2 does not have a correspondent in current version - ProblemFilters.exclude[MissingFieldProblem]("scala.Tuple2._2"), // field _2 in class scala.Tuple2 does not have a correspondent in current version - - // Scala 2 specialization - ProblemFilters.exclude[MissingClassProblem]("scala.*$sp"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.*$sp"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.*#*#sp.$init$"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.DoubleStepper"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.DoubleVectorStepper"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.IntVectorStepper"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.immutable.LongVectorStepper"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.IntStepper"), - ProblemFilters.exclude[MissingTypesProblem]("scala.collection.LongStepper"), - ProblemFilters.exclude[MissingTypesProblem]("scala.jdk.DoubleAccumulator"), - ProblemFilters.exclude[MissingTypesProblem]("scala.jdk.FunctionWrappers$*"), - ProblemFilters.exclude[MissingTypesProblem]("scala.jdk.IntAccumulator"), - ProblemFilters.exclude[MissingTypesProblem]("scala.jdk.LongAccumulator"), - ProblemFilters.exclude[FinalClassProblem]("scala.collection.ArrayOps$ReverseIterator"), - ProblemFilters.exclude[FinalClassProblem]("scala.Tuple1"), - ProblemFilters.exclude[FinalClassProblem]("scala.Tuple2"), - - // other - ProblemFilters.exclude[FinalMethodProblem]("scala.Enumeration.ValueOrdering"), - ProblemFilters.exclude[FinalMethodProblem]("scala.Enumeration.ValueSet"), - ProblemFilters.exclude[FinalMethodProblem]("scala.io.Source.NoPositioner"), - ProblemFilters.exclude[FinalMethodProblem]("scala.io.Source.RelaxedPosition"), - ProblemFilters.exclude[FinalMethodProblem]("scala.io.Source.RelaxedPositioner"), - ProblemFilters.exclude[MissingFieldProblem]("scala.collection.ArrayOps#ReverseIterator.xs"), - ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.NonLocalReturnControl.value"), - - // Missing outer pointers in private classes (not a problem) - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.LinearSeqIterator#LazyCell.this"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.mutable.PriorityQueue#ResizableArrayAccess.this"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.concurrent.BatchingExecutor#AbstractBatch.this"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.concurrent.Channel#LinkedList.this"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.IterableOnceOps#Maximized.this"), - - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.util.Sorting.scala$util$Sorting$$mergeSort$default$5"), - - ) - } + Build.stdlibBootstrappedVersion -> Seq( + // Scala language features (not really a problem) + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.language."), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.language#experimental."), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.util.Properties."), + + // Companion module class (not really a problem) + ProblemFilters.exclude[FinalClassProblem]("scala.*$"), + ProblemFilters.exclude[FinalMethodProblem]("scala.io.Source.NoPositioner"), + ProblemFilters.exclude[FinalMethodProblem]("scala.io.Source.RelaxedPosition"), + ProblemFilters.exclude[FinalMethodProblem]("scala.io.Source.RelaxedPositioner"), + ProblemFilters.exclude[FinalMethodProblem]("scala.Enumeration.ValueOrdering"), + ProblemFilters.exclude[FinalMethodProblem]("scala.Enumeration.ValueSet"), + ProblemFilters.exclude[FinalMethodProblem]("scala.StringContext.s"), + + // Issue: https://github.com/scala/scala3/issues/22495 + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.ArrayOps.scala$collection$ArrayOps$$elemTag$extension"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.ArrayOps.iterateUntilEmpty$extension"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.StringOps.isLineBreak$extension"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.StringOps.isLineBreak2$extension"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.StringOps.linesSeparated$extension"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.StringOps.escape$extension"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.StringOps.toBooleanImpl$extension"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.StringOps.unwrapArg$extension"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.StringOps.iterateUntilEmpty$extension"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuple2Zipped.coll1$extension"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuple2Zipped.coll2$extension"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuple3Zipped.coll1$extension"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuple3Zipped.coll2$extension"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuple3Zipped.coll3$extension"), + + // Issue: Scala 3 doesn't always outer pointers (not really a problem here) + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.IterableOnceOps#Maximized.this"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.LinearSeqIterator#LazyCell.this"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.mutable.PriorityQueue#ResizableArrayAccess.this"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.concurrent.BatchingExecutor#AbstractBatch.this"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.concurrent.Channel#LinkedList.this"), + ) ) val ForwardsBreakingChanges: Map[String, Seq[ProblemFilter]] = Map( diff --git a/project/ScalaLibraryPlugin.scala b/project/ScalaLibraryPlugin.scala new file mode 100644 index 000000000000..2eac7271644a --- /dev/null +++ b/project/ScalaLibraryPlugin.scala @@ -0,0 +1,108 @@ +package dotty.tools.sbtplugin + +import sbt.* +import sbt.Keys.* +import scala.jdk.CollectionConverters.* +import java.nio.file.Files + +object ScalaLibraryPlugin extends AutoPlugin { + + override def trigger = noTrigger + + val fetchScala2ClassFiles = taskKey[(Set[File], File)]("Fetch the files to use that were compiled with Scala 2") + //val scala2LibraryVersion = settingKey[String]("Version of the Scala 2 Standard Library") + + override def projectSettings = Seq ( + fetchScala2ClassFiles := { + val stream = streams.value + val cache = stream.cacheDirectory + val target = cache / "scala-library-classes" + val report = update.value + + val scalaLibraryBinaryJar = report.select( + configuration = configurationFilter(), + module = (_: ModuleID).name == "scala-library", + artifact = artifactFilter(`type` = "jar")).headOption.getOrElse { + sys.error(s"Could not fetch scala-library binary JAR") + } + + if (!target.exists()) { + IO.createDirectory(target) + } + + (FileFunction.cached(cache / "fetch-scala-library-classes", FilesInfo.lastModified, FilesInfo.exists) { _ => + stream.log.info(s"Unpacking scala-library binaries to persistent directory: ${target.getAbsolutePath}") + IO.unzip(scalaLibraryBinaryJar, target) + (target ** "*.class").get.toSet + } (Set(scalaLibraryBinaryJar)), target) + + }, + (Compile / compile) := { + val stream = streams.value + val target = (Compile / classDirectory).value + val (files, reference) = fetchScala2ClassFiles.value; + val analysis = (Compile / compile).value + stream.log.info(s"Copying files from Scala 2 Standard Library to $target") + for (file <- files; id <- file.relativeTo(reference).map(_.toString())) { + if (filesToCopy(id)) { + stream.log.debug(s"Copying file '${id}' to ${target / id}") + IO.copyFile(file, target / id) + } + } + + val overwrittenBinaries = Files.walk((Compile / classDirectory).value.toPath()) + .iterator() + .asScala + .map(_.toFile) + .map(_.relativeTo((Compile / classDirectory).value).get) + .toSet + val diff = files.filterNot(_.relativeTo(reference).exists(overwrittenBinaries)) + + IO.copy(diff.map { file => + file -> (Compile / classDirectory).value / file.relativeTo(reference).get.getPath + }) + + analysis + } + ) + + private lazy val filesToCopy = Set( + "scala/Tuple1.class", + "scala/Tuple2.class", + "scala/collection/DoubleStepper.class", + "scala/collection/IntStepper.class", + "scala/collection/LongStepper.class", + "scala/collection/immutable/DoubleVectorStepper.class", + "scala/collection/immutable/IntVectorStepper.class", + "scala/collection/immutable/LongVectorStepper.class", + "scala/jdk/DoubleAccumulator.class", + "scala/jdk/IntAccumulator.class", + "scala/jdk/LongAccumulator.class", + "scala/jdk/FunctionWrappers$FromJavaDoubleBinaryOperator.class", + "scala/jdk/FunctionWrappers$FromJavaBooleanSupplier.class", + "scala/jdk/FunctionWrappers$FromJavaDoubleConsumer.class", + "scala/jdk/FunctionWrappers$FromJavaDoublePredicate.class", + "scala/jdk/FunctionWrappers$FromJavaDoubleSupplier.class", + "scala/jdk/FunctionWrappers$FromJavaDoubleToIntFunction.class", + "scala/jdk/FunctionWrappers$FromJavaDoubleToLongFunction.class", + "scala/jdk/FunctionWrappers$FromJavaIntBinaryOperator.class", + "scala/jdk/FunctionWrappers$FromJavaDoubleUnaryOperator.class", + "scala/jdk/FunctionWrappers$FromJavaIntPredicate.class", + "scala/jdk/FunctionWrappers$FromJavaIntConsumer.class", + "scala/jdk/FunctionWrappers$FromJavaIntSupplier.class", + "scala/jdk/FunctionWrappers$FromJavaIntToDoubleFunction.class", + "scala/jdk/FunctionWrappers$FromJavaIntToLongFunction.class", + "scala/jdk/FunctionWrappers$FromJavaIntUnaryOperator.class", + "scala/jdk/FunctionWrappers$FromJavaLongBinaryOperator.class", + "scala/jdk/FunctionWrappers$FromJavaLongConsumer.class", + "scala/jdk/FunctionWrappers$FromJavaLongPredicate.class", + "scala/jdk/FunctionWrappers$FromJavaLongSupplier.class", + "scala/jdk/FunctionWrappers$FromJavaLongToDoubleFunction.class", + "scala/jdk/FunctionWrappers$FromJavaLongToIntFunction.class", + "scala/jdk/FunctionWrappers$FromJavaLongUnaryOperator.class", + "scala/collection/ArrayOps$ReverseIterator.class", + "scala/runtime/NonLocalReturnControl.class", + "scala/util/Sorting.class", "scala/util/Sorting$.class", // Contains @specialized annotation + ) + +}