From fa20dd618b96f5038713dd1fb1fbf49285cd37c5 Mon Sep 17 00:00:00 2001 From: statxc <181730535+statxc@users.noreply.github.com> Date: Sun, 12 Apr 2026 18:30:49 +0200 Subject: [PATCH] [2.x] feat: Add Best Effort compilation support for Scala 3.5+ --- main/src/main/scala/sbt/Defaults.scala | 7 ----- .../scala/sbt/internal/PluginDiscovery.scala | 1 + .../scala/sbt/plugins/BestEffortPlugin.scala | 27 ++++++++++++++++++- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 5819c6952..1b567de2c 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -204,7 +204,6 @@ object Defaults extends BuildCommon with DefExtra { testForkedParallelism :== None, javaOptions :== Nil, sbtPlugin :== false, - bestEffortEnabled :== internal.SysProp.bestEffort, isMetaBuild :== false, reresolveSbtArtifacts :== false, crossPaths :== true, @@ -1079,12 +1078,6 @@ object Defaults extends BuildCommon with DefExtra { then old ++ Seq("-Wconf:cat=unused-nowarn:s", "-Xsource:3") else old }, - scalacOptions := { - val old = scalacOptions.value - if bestEffortEnabled.value && plugins.BestEffortPlugin.isScala35Plus(scalaVersion.value) - then old ++ Seq("-Ybest-effort", "-Ywith-best-effort-tasty") - else old - }, persistJarClasspath :== true, classpathEntryDefinesClassVF := Def.uncached { val cache = diff --git a/main/src/main/scala/sbt/internal/PluginDiscovery.scala b/main/src/main/scala/sbt/internal/PluginDiscovery.scala index 934a0a53d..af28f39d0 100644 --- a/main/src/main/scala/sbt/internal/PluginDiscovery.scala +++ b/main/src/main/scala/sbt/internal/PluginDiscovery.scala @@ -51,6 +51,7 @@ object PluginDiscovery: "sbt.ScriptedPlugin" -> sbt.ScriptedPlugin, "sbt.plugins.SbtPlugin" -> sbt.plugins.SbtPlugin, "sbt.plugins.SemanticdbPlugin" -> sbt.plugins.SemanticdbPlugin, + "sbt.plugins.BestEffortPlugin" -> sbt.plugins.BestEffortPlugin, "sbt.plugins.JUnitXmlReportPlugin" -> sbt.plugins.JUnitXmlReportPlugin, "sbt.plugins.Giter8TemplatePlugin" -> sbt.plugins.Giter8TemplatePlugin, "sbt.plugins.DependencyTreePlugin" -> sbt.plugins.DependencyTreePlugin, diff --git a/main/src/main/scala/sbt/plugins/BestEffortPlugin.scala b/main/src/main/scala/sbt/plugins/BestEffortPlugin.scala index 7f8ac0aaf..3809b2771 100644 --- a/main/src/main/scala/sbt/plugins/BestEffortPlugin.scala +++ b/main/src/main/scala/sbt/plugins/BestEffortPlugin.scala @@ -9,6 +9,10 @@ package sbt package plugins +import Keys.* +import sbt.internal.SysProp +import sbt.librarymanagement.syntax.* +import ProjectExtra.inConfig import sbt.internal.inc.ScalaInstance /** @@ -21,9 +25,30 @@ import sbt.internal.inc.ScalaInstance * for improved code intelligence. */ object BestEffortPlugin extends AutoPlugin: - override def requires = JvmPlugin + override def requires = SemanticdbPlugin override def trigger = allRequirements + private val bestEffortFlags = Seq("-Ybest-effort", "-Ywith-best-effort-tasty") + + override lazy val globalSettings: Seq[Def.Setting[?]] = Seq( + bestEffortEnabled := SysProp.bestEffort, + ) + + override lazy val projectSettings: Seq[Def.Setting[?]] = + inConfig(Compile)(configurationSettings) ++ + inConfig(Test)(configurationSettings) + + lazy val configurationSettings: Seq[Def.Setting[?]] = List( + scalacOptions := { + val orig = scalacOptions.value + val enabled = bestEffortEnabled.value + val sv = scalaVersion.value + if enabled && isScala35Plus(sv) then + (orig.filterNot(bestEffortFlags.contains) ++ bestEffortFlags).distinct + else orig.filterNot(bestEffortFlags.contains) + }, + ) + private[sbt] def isScala35Plus(scalaVersion: String): Boolean = ScalaInstance.isDotty(scalaVersion) && { val versionPart = scalaVersion.stripPrefix("3.")