Skip to content

Commit 5c557cd

Browse files
committed
Fix #3882: Take LazyRefs into account for monitored subtype checking
Two types can differ only in their LazyRefs, but still need to be treated as the same for the purpose of subtype cycle checking.
1 parent c2e5011 commit 5c557cd

File tree

2 files changed

+22
-1
lines changed

2 files changed

+22
-1
lines changed

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,23 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
148148
if (Config.traceDeepSubTypeRecursions && !this.isInstanceOf[ExplainingTypeComparer])
149149
ctx.log(TypeComparer.explained(implicit ctx => ctx.typeComparer.isSubType(tp1, tp2)))
150150
}
151-
val p = (tp1, tp2)
151+
// Eliminate LazyRefs before checking whether we have seen a type before
152+
val normalize = new TypeMap {
153+
val DerefLimit = 10
154+
var derefCount = 0
155+
def apply(t: Type) = t match {
156+
case t: LazyRef =>
157+
// Dereference a lazyref to detect underlying matching types, but
158+
// be careful not to get into an infinite recursion. If recursion count
159+
// exceeds `DerefLimit`, approximate with `NoType` instead.
160+
derefCount += 1
161+
if (derefCount >= DerefLimit) NoType
162+
else try mapOver(t.ref) finally derefCount -= 1
163+
case _ =>
164+
mapOver(t)
165+
}
166+
}
167+
val p = (normalize(tp1), normalize(tp2))
152168
!pendingSubTypes(p) && {
153169
try {
154170
pendingSubTypes += p

tests/neg/i3882.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
trait Ring[A <: Ring[A]]
2+
3+
object Test {
4+
def crash[T <: Ring[_ <: T]]: Ring[T] = ??? // error: Type argument T does not conform to upper bound Ring[LazyRef(T)]
5+
}

0 commit comments

Comments
 (0)