Skip to content

Commit 4797b8a

Browse files
committed
More efficient garbage collection of type variables
When narrowing a constraint, we check if its bounds are now equal to remove it from the constraint set. This allows the corresponding type variable to be instantiated in TyperState#gc instead of accumulating uninstantiated type variables that we traverse again and again in Inferencing#interpolateTypeVars. This reduces the running time of the added testcase (copied from scala/scala#6580) from ~6 seconds to ~4 seconds. If we fully uncomment the testcase (and increase the JVM stack size), the running time goes from > 300 seconds to ~24 seconds. This is not as good as what scala/scala#6580 achieves but is already much more reasonable that what we did before.
1 parent a3c4ec7 commit 4797b8a

File tree

2 files changed

+644
-20
lines changed

2 files changed

+644
-20
lines changed

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

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -63,29 +63,34 @@ trait ConstraintHandling {
6363
}
6464
if (Config.checkConstraintsSeparated)
6565
assert(!occursIn(bound), s"$param occurs in $bound")
66-
val newBound = narrowedBound(param, bound, isUpper)
67-
val c1 = constraint.updateEntry(param, newBound)
68-
(c1 eq constraint) || {
69-
constraint = c1
70-
val TypeBounds(lo, hi) = constraint.entry(param)
71-
isSubType(lo, hi)
66+
67+
val oldBounds @ TypeBounds(lo, hi) = constraint.nonParamBounds(param)
68+
if (isUpper && (lo eq bound) || !isUpper && (bound eq hi)) {
69+
// The narrowed bounds are equal, so we can remove `param` from the constraint
70+
constraint = constraint.replace(param, bound)
71+
true
72+
}
73+
else {
74+
// Narrow one of the bounds of type parameter `param`
75+
// If `isUpper` is true, ensure that `param <: `bound`, otherwise ensure
76+
// that `param >: bound`.
77+
val narrowedBounds = {
78+
val saved = homogenizeArgs
79+
homogenizeArgs = Config.alignArgsInAnd
80+
try
81+
if (isUpper) oldBounds.derivedTypeBounds(lo, hi & bound)
82+
else oldBounds.derivedTypeBounds(lo | bound, hi)
83+
finally homogenizeArgs = saved
84+
}
85+
val c1 = constraint.updateEntry(param, narrowedBounds)
86+
(c1 eq constraint) || {
87+
constraint = c1
88+
val TypeBounds(lo, hi) = constraint.entry(param)
89+
isSubType(lo, hi)
90+
}
7291
}
7392
}
7493

75-
/** Narrow one of the bounds of type parameter `param`
76-
* If `isUpper` is true, ensure that `param <: `bound`, otherwise ensure
77-
* that `param >: bound`.
78-
*/
79-
def narrowedBound(param: TypeParamRef, bound: Type, isUpper: Boolean)(implicit ctx: Context): TypeBounds = {
80-
val oldBounds @ TypeBounds(lo, hi) = constraint.nonParamBounds(param)
81-
val saved = homogenizeArgs
82-
homogenizeArgs = Config.alignArgsInAnd
83-
try
84-
if (isUpper) oldBounds.derivedTypeBounds(lo, hi & bound)
85-
else oldBounds.derivedTypeBounds(lo | bound, hi)
86-
finally homogenizeArgs = saved
87-
}
88-
8994
private def location(implicit ctx: Context) = "" // i"in ${ctx.typerState.stateChainStr}" // use for debugging
9095

9196
protected def addUpperBound(param: TypeParamRef, bound: Type): Boolean = {

0 commit comments

Comments
 (0)