Skip to content

Commit d56de58

Browse files
committed
Eliminate LazyRefs before comparing seen types in collectCompanions
Closes scala#21521
1 parent 5e83606 commit d56de58

File tree

2 files changed

+24
-19
lines changed

2 files changed

+24
-19
lines changed

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

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -270,23 +270,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
270270
report.log(explained(_.isSubType(tp1, tp2, approx), short = false))
271271
}
272272
// Eliminate LazyRefs before checking whether we have seen a type before
273-
val normalize = new TypeMap with CaptureSet.IdempotentCaptRefMap {
274-
val DerefLimit = 10
275-
var derefCount = 0
276-
def apply(t: Type) = t match {
277-
case t: LazyRef =>
278-
// Dereference a lazyref to detect underlying matching types, but
279-
// be careful not to get into an infinite recursion. If recursion count
280-
// exceeds `DerefLimit`, approximate with `t` instead.
281-
derefCount += 1
282-
if t.evaluating || derefCount >= DerefLimit then t
283-
else try mapOver(t.ref) finally derefCount -= 1
284-
case tp: TypeVar =>
285-
tp
286-
case _ =>
287-
mapOver(t)
288-
}
289-
}
273+
val normalize = eliminateLazyRefs
290274
val p = (normalize(tp1), normalize(tp2))
291275
!pendingSubTypes.nn.contains(p) && {
292276
try {
@@ -3338,6 +3322,24 @@ object TypeComparer {
33383322
end CoveredStatus
33393323
type CoveredStatus = CoveredStatus.Repr
33403324

3325+
def eliminateLazyRefs(using Context) = new TypeMap with CaptureSet.IdempotentCaptRefMap {
3326+
val DerefLimit = 10
3327+
var derefCount = 0
3328+
def apply(t: Type) = t match {
3329+
case t: LazyRef =>
3330+
// Dereference a lazyref to detect underlying matching types, but
3331+
// be careful not to get into an infinite recursion. If recursion count
3332+
// exceeds `DerefLimit`, approximate with `t` instead.
3333+
derefCount += 1
3334+
if t.evaluating || derefCount >= DerefLimit then t
3335+
else try mapOver(t.ref) finally derefCount -= 1
3336+
case tp: TypeVar =>
3337+
tp
3338+
case _ =>
3339+
mapOver(t)
3340+
}
3341+
}
3342+
33413343
def topLevelSubType(tp1: Type, tp2: Type)(using Context): Boolean =
33423344
comparing(_.topLevelSubType(tp1, tp2))
33433345

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ trait ImplicitRunInfo:
688688
end collectParts
689689

690690
val seen = util.HashSet[Type]()
691+
val normalize = TypeComparer.eliminateLazyRefs
691692
val incomplete = util.HashSet[Type]()
692693

693694
def collectCompanions(tp: Type, parts: collection.Set[Type]): TermRefSet =
@@ -698,11 +699,13 @@ trait ImplicitRunInfo:
698699
case is: OfTypeImplicits =>
699700
is.companionRefs
700701
case null =>
701-
if seen.contains(t) then
702+
// Eliminate LazyRefs before checking whether we have seen a type before
703+
val nt = normalize(t)
704+
if seen.contains(nt) then
702705
incomplete += tp // all references for `t` will be accounted for in `seen` so we return `EmptySet`.
703706
TermRefSet.empty // on the other hand, the refs of `tp` are now inaccurate, so `tp` is marked incomplete.
704707
else
705-
seen += t
708+
seen += nt
706709
val is = recur(t)
707710
if !implicitScopeCache.contains(t) then incomplete += tp
708711
is.companionRefs

0 commit comments

Comments
 (0)