Skip to content

Commit ffe24e2

Browse files
committed
Make AproxState an opaque type
It was a value class before, and therefore suffered the boxing on comparison problem. This might save a lot of allocations (but maybe the JIT would eliminate them anyway). But anyway, it's better we dogfood Scala 3 features for this.
1 parent 0676e5a commit ffe24e2

File tree

1 file changed

+30
-27
lines changed

1 file changed

+30
-27
lines changed

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
9696
assert(canCompareAtoms == true)
9797
assert(successCount == 0)
9898
assert(totalCount == 0)
99-
assert(approx == FreshApprox)
99+
assert(approx == ApproxState.Fresh)
100100
assert(leftRoot == null)
101101
assert(frozenGadt == false)
102102

@@ -136,7 +136,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
136136
else CompareResult.OK
137137

138138
/** The current approximation state. See `ApproxState`. */
139-
private var approx: ApproxState = FreshApprox
139+
private var approx: ApproxState = ApproxState.Fresh
140140
protected def approxState: ApproxState = approx
141141

142142
/** The original left-hand type of the comparison. Gets reset
@@ -156,8 +156,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
156156
protected def isSubType(tp1: Type, tp2: Type, a: ApproxState): Boolean = {
157157
val savedApprox = approx
158158
val savedLeftRoot = leftRoot
159-
if (a == FreshApprox) {
160-
this.approx = NoApprox
159+
if (a == ApproxState.Fresh) {
160+
this.approx = ApproxState.None
161161
this.leftRoot = tp1
162162
}
163163
else this.approx = a
@@ -171,7 +171,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
171171
}
172172
}
173173

174-
def isSubType(tp1: Type, tp2: Type): Boolean = isSubType(tp1, tp2, FreshApprox)
174+
def isSubType(tp1: Type, tp2: Type): Boolean = isSubType(tp1, tp2, ApproxState.Fresh)
175175

176176
override protected def isSub(tp1: Type, tp2: Type)(using Context): Boolean = isSubType(tp1, tp2)
177177

@@ -190,7 +190,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
190190
* code would have two extra parameters for each of the many calls that go from
191191
* one sub-part of isSubType to another.
192192
*/
193-
protected def recur(tp1: Type, tp2: Type): Boolean = trace(s"isSubType ${traceInfo(tp1, tp2)} $approx", subtyping) {
193+
protected def recur(tp1: Type, tp2: Type): Boolean = trace(s"isSubType ${traceInfo(tp1, tp2)} ${approx.show}", subtyping) {
194194

195195
def monitoredIsSubType = {
196196
if (pendingSubTypes == null) {
@@ -2442,34 +2442,37 @@ object TypeComparer {
24422442
case _ => String.valueOf(res)
24432443
}
24442444

2445-
private val LoApprox = 1
2446-
private val HiApprox = 2
24472445

24482446
/** The approximation state indicates how the pair of types currently compared
24492447
* relates to the types compared originally.
2450-
* - `NoApprox`: They are still the same types
2448+
* - `None` : They are still the same types
24512449
* - `LoApprox`: The left type is approximated (i.e widened)"
24522450
* - `HiApprox`: The right type is approximated (i.e narrowed)"
24532451
*/
2454-
class ApproxState(private val bits: Int) extends AnyVal {
2455-
override def toString: String = {
2456-
val lo = if ((bits & LoApprox) != 0) "LoApprox" else ""
2457-
val hi = if ((bits & HiApprox) != 0) "HiApprox" else ""
2458-
lo ++ hi
2459-
}
2460-
def addLow: ApproxState = new ApproxState(bits | LoApprox)
2461-
def addHigh: ApproxState = new ApproxState(bits | HiApprox)
2462-
def low: Boolean = (bits & LoApprox) != 0
2463-
def high: Boolean = (bits & HiApprox) != 0
2464-
}
2452+
object ApproxState:
2453+
opaque type Repr = Int
24652454

2466-
val NoApprox: ApproxState = new ApproxState(0)
2455+
val None: Repr = 0
2456+
private val LoApprox = 1
2457+
private val HiApprox = 2
24672458

2468-
/** A special approximation state to indicate that this is the first time we
2469-
* compare (approximations of) this pair of types. It's converted to `NoApprox`
2470-
* in `isSubType`, but also leads to `leftRoot` being set there.
2471-
*/
2472-
val FreshApprox: ApproxState = new ApproxState(4)
2459+
/** A special approximation state to indicate that this is the first time we
2460+
* compare (approximations of) this pair of types. It's converted to `None`
2461+
* in `isSubType`, but also leads to `leftRoot` being set there.
2462+
*/
2463+
val Fresh: Repr = 4
2464+
2465+
extension (approx: Repr):
2466+
def low: Boolean = (approx & LoApprox) != 0
2467+
def high: Boolean = (approx & HiApprox) != 0
2468+
def addLow: Repr = approx | LoApprox
2469+
def addHigh: Repr = approx | HiApprox
2470+
def show: String =
2471+
val lo = if low then "LoApprox" else ""
2472+
val hi = if high then "HiApprox" else ""
2473+
lo ++ hi
2474+
end ApproxState
2475+
type ApproxState = ApproxState.Repr
24732476

24742477
def topLevelSubType(tp1: Type, tp2: Type)(using Context): Boolean =
24752478
comparing(_.topLevelSubType(tp1, tp2))
@@ -2745,7 +2748,7 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
27452748
if Config.verboseExplainSubtype || ctx.settings.verbose.value
27462749
then s" ${tp1.getClass} ${tp2.getClass}"
27472750
else ""
2748-
traceIndented(s"${show(tp1)} <:< ${show(tp2)}$moreInfo $approx ${if (frozenConstraint) " frozen" else ""}") {
2751+
traceIndented(s"${show(tp1)} <:< ${show(tp2)}$moreInfo ${approx.show} ${if (frozenConstraint) " frozen" else ""}") {
27492752
super.isSubType(tp1, tp2, approx)
27502753
}
27512754

0 commit comments

Comments
 (0)