Skip to content

Commit fa5ab27

Browse files
committed
performance improvements for less eager dealiasing
1 parent 9df79a1 commit fa5ab27

File tree

1 file changed

+36
-30
lines changed

1 file changed

+36
-30
lines changed

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

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,37 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
132132
}
133133

134134
def necessarySubType(tp1: Type, tp2: Type): Boolean =
135+
inline def followAlias[T](inline tp: Type)(inline default: T)(inline f: (TypeProxy, Symbol) => T): T =
136+
tp match
137+
case tp: (AppliedType | TypeRef) => f(tp, tp.typeSymbol)
138+
case _ => default
139+
140+
@tailrec def aliasedSymbols(tp: Type, result: Set[Symbol] = Set.empty): Set[Symbol] =
141+
followAlias(tp)(result) { (tp, sym) =>
142+
if sym.isAliasType then aliasedSymbols(tp.superType, result + sym)
143+
else if sym.exists && (sym ne AnyClass) then result + sym
144+
else result
145+
}
146+
147+
@tailrec def dealias(tp: Type, syms: Set[Symbol]): Type =
148+
followAlias(tp)(NoType) { (tp, sym) =>
149+
if syms contains sym then tp
150+
else if sym.isAliasType then dealias(tp.superType, syms)
151+
else NoType
152+
}
153+
135154
val saved = myNecessaryConstraintsOnly
136155
myNecessaryConstraintsOnly = true
137-
try topLevelSubType(tp1, tp2)
138-
finally myNecessaryConstraintsOnly = saved
156+
157+
try
158+
val tryDealias = (tp2 ne tp1) && (tp2 ne WildcardType) && followAlias(tp1)(false) { (_, sym) => sym.isAliasType }
159+
if tryDealias then
160+
topLevelSubType(dealias(tp1, aliasedSymbols(tp2)) orElse tp1, tp2)
161+
else
162+
topLevelSubType(tp1, tp2)
163+
finally
164+
myNecessaryConstraintsOnly = saved
165+
end necessarySubType
139166

140167
def testSubType(tp1: Type, tp2: Type): CompareResult =
141168
GADTused = false
@@ -179,37 +206,16 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
179206
try op finally comparedTypeLambdas = saved
180207

181208
protected def isSubType(tp1: Type, tp2: Type, a: ApproxState): Boolean = {
182-
inline def followAlias[T](inline tp: Type)(inline default: T)(inline f: (TypeProxy, Symbol) => T): T =
183-
tp.stripAnnots.stripTypeVar match
184-
case tp: (AppliedType | TypeRef) => f(tp, tp.typeSymbol)
185-
case _ => default
186-
187-
@tailrec def dealias(tp: Type, syms: Set[Symbol]): Type =
188-
followAlias(tp)(NoType) { (tp, sym) =>
189-
if syms contains sym then tp
190-
else if sym.isAliasType then dealias(tp.superType, syms)
191-
else NoType
192-
}
193-
194-
@tailrec def aliasedSymbols(tp: Type, result: Set[Symbol] = Set.empty): Set[Symbol] =
195-
followAlias(tp)(Set.empty) { (tp, sym) =>
196-
if sym.isAliasType then aliasedSymbols(tp.superType, result + sym)
197-
else if sym.exists && (sym ne AnyClass) then result + sym
198-
else Set.empty
199-
}
200-
201-
val tp1dealiased = dealias(tp1, aliasedSymbols(tp2)) orElse tp1
202-
203209
val savedApprox = approx
204210
val savedLeftRoot = leftRoot
205211
if (a == ApproxState.Fresh) {
206212
this.approx = ApproxState.None
207-
this.leftRoot = tp1dealiased
213+
this.leftRoot = tp1
208214
}
209215
else this.approx = a
210-
try recur(tp1dealiased, tp2)
216+
try recur(tp1, tp2)
211217
catch {
212-
case ex: Throwable => handleRecursive("subtype", i"$tp1dealiased <:< $tp2", ex, weight = 2)
218+
case ex: Throwable => handleRecursive("subtype", i"$tp1 <:< $tp2", ex, weight = 2)
213219
}
214220
finally {
215221
this.approx = savedApprox
@@ -407,14 +413,14 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
407413
case tp2: TypeParamRef =>
408414
constraint.entry(tp2) match {
409415
case TypeBounds(lo, hi) =>
410-
val aliasLo = tp1 != lo && info1.alias == lo
411-
val aliasHi = tp1 != hi && info1.alias == hi
416+
val aliasLo = (tp1 ne lo) && (info1.alias eq lo)
417+
val aliasHi = (tp1 ne hi) && (info1.alias eq hi)
412418
if aliasLo || aliasHi then
413419
constraint = constraint.updateEntry(tp2, TypeBounds(
414420
if aliasLo then tp1 else lo,
415421
if aliasHi then tp1 else hi))
416422
case tp =>
417-
if tp1 != tp && info1.alias == tp then
423+
if (tp1 ne tp) && (info1.alias eq tp) then
418424
constraint = constraint.updateEntry(tp2, tp1)
419425
}
420426
case _ =>
@@ -1049,7 +1055,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
10491055
def isMatchingApply(tp1: Type): Boolean = tp1.widen match {
10501056
case tp1 @ AppliedType(tycon1, args1) =>
10511057
// We intentionally do not automatically dealias `tycon1` or `tycon2` here.
1052-
// `isSubType` already takes care of dealiasing type
1058+
// `necessarySubType` already takes care of dealiasing type
10531059
// constructors when this can be done without affecting type
10541060
// inference, doing it here would not only prevent code from compiling
10551061
// but could also result in the wrong thing being inferred later, for example

0 commit comments

Comments
 (0)