Skip to content

Commit

Permalink
Eliminate LazyRefs before comparing seen types in collectCompanions
Browse files Browse the repository at this point in the history
  • Loading branch information
wjoel committed Aug 30, 2024
1 parent 5e83606 commit d56de58
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 19 deletions.
36 changes: 19 additions & 17 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -270,23 +270,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
report.log(explained(_.isSubType(tp1, tp2, approx), short = false))
}
// Eliminate LazyRefs before checking whether we have seen a type before
val normalize = new TypeMap with CaptureSet.IdempotentCaptRefMap {
val DerefLimit = 10
var derefCount = 0
def apply(t: Type) = t match {
case t: LazyRef =>
// Dereference a lazyref to detect underlying matching types, but
// be careful not to get into an infinite recursion. If recursion count
// exceeds `DerefLimit`, approximate with `t` instead.
derefCount += 1
if t.evaluating || derefCount >= DerefLimit then t
else try mapOver(t.ref) finally derefCount -= 1
case tp: TypeVar =>
tp
case _ =>
mapOver(t)
}
}
val normalize = eliminateLazyRefs
val p = (normalize(tp1), normalize(tp2))
!pendingSubTypes.nn.contains(p) && {
try {
Expand Down Expand Up @@ -3338,6 +3322,24 @@ object TypeComparer {
end CoveredStatus
type CoveredStatus = CoveredStatus.Repr

def eliminateLazyRefs(using Context) = new TypeMap with CaptureSet.IdempotentCaptRefMap {
val DerefLimit = 10
var derefCount = 0
def apply(t: Type) = t match {
case t: LazyRef =>
// Dereference a lazyref to detect underlying matching types, but
// be careful not to get into an infinite recursion. If recursion count
// exceeds `DerefLimit`, approximate with `t` instead.
derefCount += 1
if t.evaluating || derefCount >= DerefLimit then t
else try mapOver(t.ref) finally derefCount -= 1
case tp: TypeVar =>
tp
case _ =>
mapOver(t)
}
}

def topLevelSubType(tp1: Type, tp2: Type)(using Context): Boolean =
comparing(_.topLevelSubType(tp1, tp2))

Expand Down
7 changes: 5 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,7 @@ trait ImplicitRunInfo:
end collectParts

val seen = util.HashSet[Type]()
val normalize = TypeComparer.eliminateLazyRefs
val incomplete = util.HashSet[Type]()

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

0 comments on commit d56de58

Please sign in to comment.