Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add plugin to copy binary files from the scala 2 artefacts #22480

Merged
merged 2 commits into from
Mar 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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._
Expand Down Expand Up @@ -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).
Expand Down
115 changes: 38 additions & 77 deletions project/Scala2LibraryBootstrappedMiMaFilters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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.<clinit>"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.language#experimental.<clinit>"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.util.Properties.<clinit>"),
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.<clinit>"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.language#experimental.<clinit>"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.util.Properties.<clinit>"),

// 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(
Expand Down
108 changes: 108 additions & 0 deletions project/ScalaLibraryPlugin.scala
Original file line number Diff line number Diff line change
@@ -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
)

}
Loading