From d9f60b6cfde0ed30290de4aefa7453d316b8acc2 Mon Sep 17 00:00:00 2001 From: kenji yoshida <6b656e6a69@gmail.com> Date: Fri, 14 Aug 2026 02:48:02 +0900 Subject: [PATCH] [2.x] refactor: Add tailrec annotation (#9591) --- main/src/main/scala/sbt/ProjectExtra.scala | 2 ++ server-test/src/test/scala/testpkg/BuildServerTest.scala | 2 ++ util-cache/src/main/scala/sbt/util/ActionCache.scala | 3 ++- util-collection/src/test/scala/DagSpecification.scala | 2 ++ 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/main/src/main/scala/sbt/ProjectExtra.scala b/main/src/main/scala/sbt/ProjectExtra.scala index de0a13e2b..873f34902 100755 --- a/main/src/main/scala/sbt/ProjectExtra.scala +++ b/main/src/main/scala/sbt/ProjectExtra.scala @@ -10,6 +10,7 @@ package sbt import java.io.File import java.nio.file.Path as NioPath import java.net.URI +import scala.annotation.tailrec // import Project._ import Keys.{ stateBuildStructure, @@ -616,6 +617,7 @@ trait ProjectExtra extends Scoped.Syntax: projectRef: ProjectRef ): Seq[ProjectRef] = { def dependencies(map: Map[ProjectRef, Seq[ProjectRef]], id: ProjectRef): Set[ProjectRef] = { + @tailrec def helper(map: Map[ProjectRef, Seq[ProjectRef]], acc: Set[ProjectRef]): Set[ProjectRef] = if (acc.exists(map.contains)) { val (kept, rem) = map.partition { case (k, _) => acc(k) } diff --git a/server-test/src/test/scala/testpkg/BuildServerTest.scala b/server-test/src/test/scala/testpkg/BuildServerTest.scala index d36aae8f7..5e8a4ff38 100644 --- a/server-test/src/test/scala/testpkg/BuildServerTest.scala +++ b/server-test/src/test/scala/testpkg/BuildServerTest.scala @@ -20,6 +20,7 @@ import java.io.File import java.net.URI import java.nio.file.{ Files, Paths } import java.util.concurrent.TimeoutException +import scala.annotation.tailrec import scala.concurrent.duration.* import scala.util.{ Failure, Success } @@ -303,6 +304,7 @@ class BuildServerTest extends AbstractServerTest { "diagnostics for Diagnostics.scala after a failed compile (#9345)" ) + @tailrec def drainQueuedNotificationsAndFailOnForbiddenReset(): Unit = svr.session.waitForNotificationMsg(Duration.Zero)(_ => true) match { case Success(n) => diff --git a/util-cache/src/main/scala/sbt/util/ActionCache.scala b/util-cache/src/main/scala/sbt/util/ActionCache.scala index 292fdadff..99d1ae961 100644 --- a/util-cache/src/main/scala/sbt/util/ActionCache.scala +++ b/util-cache/src/main/scala/sbt/util/ActionCache.scala @@ -32,7 +32,7 @@ import sbt.nio.file.{ **, FileTreeView } import sbt.nio.file.syntax.* import sbt.util.CacheImplicits import scala.reflect.ClassTag -import scala.annotation.{ meta, StaticAnnotation } +import scala.annotation.{ meta, tailrec, StaticAnnotation } import scala.collection.mutable import scala.util.control.NonFatal import sjsonnew.{ HashWriter, JsonFormat } @@ -329,6 +329,7 @@ object ActionCache: ) /** Walks `t`'s cause chain for a `NoSuchFileException`, returning the missing file's path. */ + @tailrec private[sbt] def findMissingFile(t: Throwable): Option[String] = t match case null => None diff --git a/util-collection/src/test/scala/DagSpecification.scala b/util-collection/src/test/scala/DagSpecification.scala index 45bb8cecc..3c301a664 100644 --- a/util-collection/src/test/scala/DagSpecification.scala +++ b/util-collection/src/test/scala/DagSpecification.scala @@ -11,6 +11,7 @@ package sbt.internal.util import org.scalacheck.* import Prop.* +import scala.annotation.tailrec import scala.collection.mutable.HashSet object DagSpecification extends Properties("Dag") { @@ -41,6 +42,7 @@ object DagSpecification extends Properties("Dag") { private def isSet[T](c: Seq[T]) = Set(c*).size == c.size private def dependenciesPrecedeNodes(sort: List[TestDag]) = { val seen = new HashSet[TestDag] + @tailrec def iterate(remaining: List[TestDag]): Boolean = { remaining match { case Nil => true