Skip to content

Commit a91d483

Browse files
committed
Tailrec patrol: src/library
- mark methods that are tailrec as such - make some more methods tailrec by making them final
1 parent ca68c51 commit a91d483

File tree

14 files changed

+42
-12
lines changed

14 files changed

+42
-12
lines changed

src/library/scala/collection/Iterator.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite
530530
private[this] var nextElementDefined: Boolean = false
531531
private[this] var nextElement: A = _
532532

533+
@tailrec
533534
def hasNext: Boolean = nextElementDefined || (self.hasNext && {
534535
val a = self.next()
535536
if (traversedValues.add(f(a))) {
@@ -637,7 +638,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite
637638
* iterator is referring (the finish() method) and thus triggering
638639
* handling of structural calls. It's not what's intended here.
639640
*/
640-
class Leading extends AbstractIterator[A] {
641+
final class Leading extends AbstractIterator[A] {
641642
private[this] var lookahead: mutable.Queue[A] = null
642643
private[this] var hd: A = _
643644
/* Status is kept with magic numbers
@@ -670,6 +671,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite
670671
}
671672
else Iterator.empty.next()
672673
}
674+
@tailrec
673675
def finish(): Boolean = status match {
674676
case -2 => status = -1 ; true
675677
case -1 => false

src/library/scala/collection/StringParsers.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ private[scala] object StringParsers {
178178
//some utilities for working with index bounds into the original string
179179
@inline
180180
def forAllBetween(start: Int, end: Int, pred: Char => Boolean): Boolean = {
181+
@tailrec
181182
def rec(i: Int): Boolean = i >= end || pred(format.charAt(i)) && rec(i + 1)
182183
rec(start)
183184
}

src/library/scala/collection/View.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ package scala.collection
1414

1515
import java.io.{ObjectInputStream, ObjectOutputStream}
1616

17+
import scala.annotation.tailrec
1718
import scala.collection.mutable.{ArrayBuffer, Builder}
1819
import scala.collection.immutable.LazyList
1920

@@ -169,6 +170,7 @@ object View extends IterableFactory[View] {
169170
private[this] var hd: A1 = _
170171
private[this] var hdDefined: Boolean = false
171172
def hasNext = hdDefined || {
173+
@tailrec
172174
def findNext(): Boolean =
173175
if (self.hasNext) {
174176
f(self.next()) match {
@@ -193,6 +195,7 @@ object View extends IterableFactory[View] {
193195
private[this] var hd: A2 = _
194196
private[this] var hdDefined: Boolean = false
195197
def hasNext = hdDefined || {
198+
@tailrec
196199
def findNext(): Boolean =
197200
if (self.hasNext) {
198201
f(self.next()) match {

src/library/scala/collection/concurrent/TrieMap.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1038,7 +1038,7 @@ object TrieMap extends MapFactory[TrieMap] {
10381038
}
10391039

10401040

1041-
private[collection] class TrieMapIterator[K, V](var level: Int, private var ct: TrieMap[K, V], mustInit: Boolean = true) extends AbstractIterator[(K, V)] {
1041+
private[collection] final class TrieMapIterator[K, V](var level: Int, private var ct: TrieMap[K, V], mustInit: Boolean = true) extends AbstractIterator[(K, V)] {
10421042
private val stack = new Array[Array[BasicNode]](7)
10431043
private val stackpos = new Array[Int](7)
10441044
private var depth = -1
@@ -1088,6 +1088,7 @@ private[collection] class TrieMapIterator[K, V](var level: Int, private var ct:
10881088
readin(r)
10891089
}
10901090

1091+
@tailrec
10911092
def advance(): Unit = if (depth >= 0) {
10921093
val npos = stackpos(depth) + 1
10931094
if (npos < stack(depth).length) {

src/library/scala/collection/immutable/IntMap.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ private[immutable] abstract class IntMapIterator[V, T](it: IntMap[V]) extends Ab
133133
def valueOf(tip: IntMap.Tip[V]): T
134134

135135
def hasNext = index != 0
136+
@tailrec
136137
final def next(): T =
137138
pop match {
138139
case IntMap.Bin(_,_, t@IntMap.Tip(_, _), right) => {
@@ -285,19 +286,22 @@ sealed abstract class IntMap[+T] extends AbstractMap[Int, T]
285286
case IntMap.Bin(_, _, left, right) => left.size + right.size
286287
}
287288

289+
@tailrec
288290
final def get(key: Int): Option[T] = this match {
289291
case IntMap.Bin(prefix, mask, left, right) => if (zero(key, mask)) left.get(key) else right.get(key)
290292
case IntMap.Tip(key2, value) => if (key == key2) Some(value) else None
291293
case IntMap.Nil => None
292294
}
293295

296+
@tailrec
294297
final override def getOrElse[S >: T](key: Int, default: => S): S = this match {
295298
case IntMap.Nil => default
296299
case IntMap.Tip(key2, value) => if (key == key2) value else default
297300
case IntMap.Bin(prefix, mask, left, right) =>
298301
if (zero(key, mask)) left.getOrElse(key, default) else right.getOrElse(key, default)
299302
}
300303

304+
@tailrec
301305
final override def apply(key: Int): T = this match {
302306
case IntMap.Bin(prefix, mask, left, right) => if (zero(key, mask)) left(key) else right(key)
303307
case IntMap.Tip(key2, value) => if (key == key2) value else throw new IllegalArgumentException("Key not found")

src/library/scala/collection/immutable/List.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ sealed abstract class List[+A]
437437
@`inline` final def mapConserve[B >: A <: AnyRef](f: A => B): List[B] = {
438438
// Note to developers: there exists a duplication between this function and `reflect.internal.util.Collections#map2Conserve`.
439439
// If any successful optimization attempts or other changes are made, please rehash them there too.
440-
//@tailrec
440+
@tailrec
441441
def loop(mappedHead: List[B], mappedLast: ::[B], unchanged: List[A], pending: List[A]): List[B] = {
442442
if (pending.isEmpty) {
443443
if (mappedHead eq null) unchanged

src/library/scala/collection/immutable/LongMap.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ private[immutable] abstract class LongMapIterator[V, T](it: LongMap[V]) extends
130130
def valueOf(tip: LongMap.Tip[V]): T
131131

132132
def hasNext = index != 0
133+
@tailrec
133134
final def next(): T =
134135
pop() match {
135136
case LongMap.Bin(_,_, t@LongMap.Tip(_, _), right) => {
@@ -280,19 +281,22 @@ sealed abstract class LongMap[+T] extends AbstractMap[Long, T]
280281
case LongMap.Bin(_, _, left, right) => left.size + right.size
281282
}
282283

284+
@tailrec
283285
final def get(key: Long): Option[T] = this match {
284286
case LongMap.Bin(prefix, mask, left, right) => if (zero(key, mask)) left.get(key) else right.get(key)
285287
case LongMap.Tip(key2, value) => if (key == key2) Some(value) else None
286288
case LongMap.Nil => None
287289
}
288290

291+
@tailrec
289292
final override def getOrElse[S >: T](key: Long, default: => S): S = this match {
290293
case LongMap.Nil => default
291294
case LongMap.Tip(key2, value) => if (key == key2) value else default
292295
case LongMap.Bin(prefix, mask, left, right) =>
293296
if (zero(key, mask)) left.getOrElse(key, default) else right.getOrElse(key, default)
294297
}
295298

299+
@tailrec
296300
final override def apply(key: Long): T = this match {
297301
case LongMap.Bin(prefix, mask, left, right) => if (zero(key, mask)) left(key) else right(key)
298302
case LongMap.Tip(key2, value) => if (key == key2) value else throw new IllegalArgumentException("Key not found")

src/library/scala/collection/immutable/TreeSeqMap.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
package scala
1414
package collection
1515
package immutable
16-
16+
17+
import scala.annotation.tailrec
18+
1719
/** This class implements an immutable map that preserves order using
1820
* a hash map for the key to value mapping to provide efficient lookup,
1921
* and a tree for the ordering of the keys to provide efficient
@@ -383,6 +385,7 @@ object TreeSeqMap extends MapFactory[TreeSeqMap] {
383385
if (it != Zero) push(it)
384386

385387
def hasNext = index != 0
388+
@tailrec
386389
def next(): V =
387390
pop match {
388391
case Bin(_,_, Tip(_, v), right) =>

src/library/scala/reflect/ClassManifestDeprecatedApis.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
package scala
1414
package reflect
1515

16-
import scala.collection.mutable.{ ArraySeq, ArrayBuilder }
17-
import java.lang.{ Class => jClass }
16+
import scala.collection.mutable.{ArrayBuilder, ArraySeq}
17+
import java.lang.{Class => jClass}
18+
19+
import scala.annotation.tailrec
1820

1921
@deprecated("use scala.reflect.ClassTag instead", "2.10.0")
2022
trait ClassManifestDeprecatedApis[T] extends OptManifest[T] {
@@ -25,6 +27,7 @@ trait ClassManifestDeprecatedApis[T] extends OptManifest[T] {
2527
def erasure: jClass[_] = runtimeClass
2628

2729
private def subtype(sub: jClass[_], sup: jClass[_]): Boolean = {
30+
@tailrec
2831
def loop(left: Set[jClass[_]], seen: Set[jClass[_]]): Boolean = {
2932
left.nonEmpty && {
3033
val next = left.head

src/library/scala/sys/process/BasicIO.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ object BasicIO {
195195
def processLinesFully(processLine: String => Unit)(readLine: () => String): Unit = {
196196
def working = (Thread.currentThread.isInterrupted == false)
197197
def halting = { Thread.currentThread.interrupt(); null }
198+
@tailrec
198199
def readFully(): Unit =
199200
if (working) {
200201
val line =

0 commit comments

Comments
 (0)