From 611cea8fbd994eb957c981f0de0877cde9754317 Mon Sep 17 00:00:00 2001 From: kenji yoshida <6b656e6a69@gmail.com> Date: Mon, 23 Feb 2026 12:20:46 +0900 Subject: [PATCH] Add tailrec annotations (#8785) --- .../src/main/scala/sbt/internal/EvaluateConfigurations.scala | 2 ++ .../src/main/scala/sbt/internal/parser/SbtRefactorings.scala | 2 ++ .../src/main/scala/sbt/internal/util/complete/Parser.scala | 3 +++ .../src/main/scala/sbt/internal/util/Settings.scala | 2 ++ 4 files changed, 9 insertions(+) diff --git a/buildfile/src/main/scala/sbt/internal/EvaluateConfigurations.scala b/buildfile/src/main/scala/sbt/internal/EvaluateConfigurations.scala index 3458877cf..668901dcc 100644 --- a/buildfile/src/main/scala/sbt/internal/EvaluateConfigurations.scala +++ b/buildfile/src/main/scala/sbt/internal/EvaluateConfigurations.scala @@ -17,6 +17,7 @@ import Def.{ ScopedKey, Setting, Settings } import Scope.GlobalScope import sbt.internal.parser.SbtParser import sbt.io.IO +import scala.annotation.tailrec import scala.jdk.CollectionConverters.* import xsbti.PathBasedFile import xsbti.VirtualFile @@ -299,6 +300,7 @@ private[sbt] object EvaluateConfigurations { ): (Seq[(String, Tree, LineRange)], Seq[(String, Tree, LineRange)]) = lines partition { case (_, tree, _) => isDefinition(tree) } + @tailrec private def isDefinition(tree: Tree): Boolean = { tree match { case Annotated(arg, annot) => isDefinition(arg) diff --git a/buildfile/src/main/scala/sbt/internal/parser/SbtRefactorings.scala b/buildfile/src/main/scala/sbt/internal/parser/SbtRefactorings.scala index 13ccc9b2b..36d67a9cd 100644 --- a/buildfile/src/main/scala/sbt/internal/parser/SbtRefactorings.scala +++ b/buildfile/src/main/scala/sbt/internal/parser/SbtRefactorings.scala @@ -11,6 +11,7 @@ package parser import dotty.tools.dotc.ast.untpd import dotty.tools.dotc.core.Contexts.Context +import scala.annotation.tailrec private[sbt] object SbtRefactorings: @@ -91,6 +92,7 @@ private[sbt] object SbtRefactorings: seq.toMap } + @tailrec private def extractSettingName(tree: untpd.Tree): String = tree match case untpd.Ident(name) => name.toString case untpd.InfixOp(lhs, _, _) => extractSettingName(lhs) diff --git a/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parser.scala b/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parser.scala index 5549de44a..9bb7781a9 100644 --- a/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parser.scala +++ b/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parser.scala @@ -12,6 +12,7 @@ package complete import Parser.* import sbt.internal.util.Types.{ left, right, some } import sbt.internal.util.Util.{ makeList, separate } +import scala.annotation.tailrec /** * A String parser that provides semi-automatic tab completion. A successful parse results in a @@ -505,6 +506,7 @@ trait ParserMain { // intended to be temporary pending proper error feedback def result[T](p: Parser[T], s: String): Either[() => (Seq[String], Int), T] = { + @tailrec def loop(i: Int, a: Parser[T]): Either[() => (Seq[String], Int), T] = a match { case Invalid(f) => Left(() => (f.errors, i)) @@ -1003,6 +1005,7 @@ private final class Repeat[T]( repeat(Some(repeated.derive(c)), repeated, scala.math.max(0, min - 1), max.decrement, accRev) def completions(level: Int) = { + @tailrec def pow(comp: Completions, exp: Completions, n: Int): Completions = if (n == 1) comp else pow(comp.x(exp), exp, n - 1) diff --git a/util-collection/src/main/scala/sbt/internal/util/Settings.scala b/util-collection/src/main/scala/sbt/internal/util/Settings.scala index 6295f5a04..e75031531 100644 --- a/util-collection/src/main/scala/sbt/internal/util/Settings.scala +++ b/util-collection/src/main/scala/sbt/internal/util/Settings.scala @@ -10,6 +10,7 @@ package sbt.internal.util import Types.* import sbt.util.Show import Util.{ nil, nilSeq } +import scala.annotation.tailrec import scala.jdk.CollectionConverters.* // delegates should contain the input ScopeType as the first entry @@ -590,6 +591,7 @@ trait Init: val processed = new mutable.HashSet[ScopedKey[?]] // derives settings, transitively so that a derived setting can trigger another + @tailrec def process(rem: List[Setting[?]]): Unit = rem match { case s :: ss => val sk = s.key