Skip to content

Commit 14689bf

Browse files
committed
Avoid cycles when adding bounds to constraints
1 parent 247cc86 commit 14689bf

File tree

1 file changed

+21
-16
lines changed

1 file changed

+21
-16
lines changed

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

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -86,22 +86,24 @@ trait ConstraintHandling[AbstractContext] {
8686
def fullBounds(param: TypeParamRef)(implicit actx: AbstractContext): TypeBounds =
8787
nonParamBounds(param).derivedTypeBounds(fullLowerBound(param), fullUpperBound(param))
8888

89-
protected def addOneBound(param: TypeParamRef, bound: Type, isUpper: Boolean)(implicit actx: AbstractContext): Boolean =
89+
protected def addOneBound(param: TypeParamRef, rawBound: Type, isUpper: Boolean)(implicit actx: AbstractContext): Boolean =
9090
!constraint.contains(param) || {
91-
def occursIn(bound: Type): Boolean = {
92-
val b = bound.dealias
93-
(b eq param) || {
94-
b match {
95-
case b: AndType => occursIn(b.tp1) || occursIn(b.tp2)
96-
case b: OrType => occursIn(b.tp1) || occursIn(b.tp2)
97-
case b: TypeVar => occursIn(b.origin)
98-
case b: TermRef => occursIn(b.underlying)
99-
case _ => false
100-
}
101-
}
102-
}
103-
if (Config.checkConstraintsSeparated)
104-
assert(!occursIn(bound), s"$param occurs in $bound")
91+
def avoidCycle(tp: Type): Type = tp match
92+
case tp: AndOrType =>
93+
tp.derivedAndOrType(avoidCycle(tp.tp1), avoidCycle(tp.tp2))
94+
case tp: TypeParamRef =>
95+
if tp eq param then
96+
//println(i"stripping $tp from $rawBound, upper = $isUpper in $constraint")
97+
if isUpper then defn.AnyType else defn.NothingType
98+
else constraint.entry(tp) match
99+
case TypeBounds(lo, hi) => if lo eq hi then avoidCycle(lo) else tp
100+
case inst => avoidCycle(inst)
101+
case tp: TypeVar =>
102+
val underlying1 = avoidCycle(tp.underlying)
103+
if underlying1 eq tp.underlying then tp else underlying1
104+
case _ =>
105+
tp
106+
val bound = avoidCycle(rawBound)
105107

106108
val oldBounds @ TypeBounds(lo, hi) = constraint.nonParamBounds(param)
107109
val equalBounds = isUpper && (lo eq bound) || !isUpper && (bound eq hi)
@@ -275,6 +277,9 @@ trait ConstraintHandling[AbstractContext] {
275277
// from above | hi lo lo
276278
//
277279
if (variance == 0 || fromBelow == (variance < 0)) bounds.lo else bounds.hi
280+
case `param` =>
281+
if variance == 0 || fromBelow == (variance < 0) then defn.AnyType
282+
else defn.NothingType
278283
case _ => tp
279284
}
280285
}
@@ -483,7 +488,7 @@ trait ConstraintHandling[AbstractContext] {
483488
if bnd eq param then // (1)
484489
if fromBelow then defn.NothingType else defn.AnyType
485490
else constraint.entry(bnd) match
486-
case _: TypeBounds => bnd
491+
case TypeBounds(lo, hi) => if lo eq hi then prune(lo) else bnd
487492
case inst => prune(inst) // (3)
488493
case bnd: ExprType => // (4)
489494
// ExprTypes are not value types, so type parameters should not

0 commit comments

Comments
 (0)