Skip to content

Eliminate LazyRefs before comparing seen types in collectCompanions #21522

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading