Skip to content

Commit 4127cee

Browse files
committed
Use LinearSet instead of mutable.HashSet in TailRec
1 parent 79edb79 commit 4127cee

File tree

2 files changed

+49
-2
lines changed

2 files changed

+49
-2
lines changed

compiler/src/dotty/tools/dotc/transform/TailRec.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import core.StdNames.nme
1313
import core.Symbols._
1414
import reporting._
1515
import transform.MegaPhase.MiniPhase
16+
import util.LinearSet
1617

1718
import scala.collection.mutable
1819

@@ -258,7 +259,7 @@ class TailRec extends MiniPhase {
258259
}
259260

260261
/** Symbols of Labeled blocks that are in tail position. */
261-
private val tailPositionLabeledSyms = new mutable.HashSet[Symbol]()
262+
private var tailPositionLabeledSyms = LinearSet.empty[Symbol]
262263

263264
private var inTailPosition = true
264265

@@ -283,7 +284,7 @@ class TailRec extends MiniPhase {
283284
* a recursive call of a @tailrec annotated method (i.e. `isMandatory`).
284285
*/
285286
private def isTraversalNeeded =
286-
isMandatory || tailPositionLabeledSyms.nonEmpty
287+
isMandatory || tailPositionLabeledSyms.size > 0
287288

288289
def noTailTransform(tree: Tree)(using Context): Tree =
289290
if (isTraversalNeeded) transform(tree, tailPosition = false)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package dotty.tools.dotc.util
2+
import collection.immutable
3+
4+
/** A linear identity set is a set that uses `eq` as the underlying
5+
* equality where after a `+` the previous set value cannot be used anymore.
6+
* The set is implemented as an immutable set for
7+
* sizes <= 4 and as a HashSet for larger sizes.
8+
*/
9+
opaque type LinearSet[Elem >: Null <: AnyRef] =
10+
immutable.Set[Elem] | HashSet[Elem]
11+
12+
object LinearSet:
13+
14+
def empty[Elem >: Null <: AnyRef]: LinearSet[Elem] = immutable.Set.empty[Elem]
15+
16+
extension [Elem >: Null <: AnyRef](s: LinearSet[Elem]):
17+
18+
def contains(elem: Elem): Boolean = (s: @unchecked) match
19+
case s: immutable.AbstractSet[Elem] @unchecked => s.contains(elem)
20+
case s: HashSet[Elem] @unchecked => s.contains(elem)
21+
22+
def + (elem: Elem): LinearSet[Elem] = (s: @unchecked) match
23+
case s: immutable.AbstractSet[Elem] @unchecked =>
24+
if s.size < 4 then
25+
s + elem
26+
else
27+
val s1 = HashSet[Elem](initialCapacity = 8)
28+
s.foreach(s1 += _)
29+
s1 += elem
30+
s1
31+
case s: HashSet[Elem] @unchecked =>
32+
s += elem
33+
s
34+
35+
def - (elem: Elem): LinearSet[Elem] = (s: @unchecked) match
36+
case s: immutable.AbstractSet[Elem] @unchecked =>
37+
s - elem
38+
case s: HashSet[Elem] @unchecked =>
39+
s -= elem
40+
s
41+
42+
def size = (s: @unchecked) match
43+
case s: immutable.AbstractSet[Elem] @unchecked => s.size
44+
case s: HashSet[Elem] @unchecked => s.size
45+
46+
end LinearSet

0 commit comments

Comments
 (0)