@@ -295,11 +295,24 @@ trait ConstraintHandling {
295295 end legalBound
296296
297297 protected def addOneBound (param : TypeParamRef , rawBound : Type , isUpper : Boolean )(using Context ): Boolean =
298+
299+ // Replace top-level occurrences of `param` in `bound` by `Nothing`
300+ def sanitize (bound : Type ): Type =
301+ if bound.stripped eq param then defn.NothingType
302+ else bound match
303+ case bound : AndOrType =>
304+ bound.derivedAndOrType(sanitize(bound.tp1), sanitize(bound.tp2))
305+ case _ =>
306+ bound
307+
298308 if ! constraint.contains(param) then true
299- else if ! isUpper && param.occursIn(rawBound) then
300- // We don't allow recursive lower bounds when defining a type,
301- // so we shouldn't allow them as constraints either.
302- false
309+ else if ! isUpper && param.occursIn(rawBound.widen) then
310+ val rawBound1 = sanitize(rawBound.widenDealias)
311+ if param.occursIn(rawBound1) then
312+ // We don't allow recursive lower bounds when defining a type,
313+ // so we shouldn't allow them as constraints either.
314+ false
315+ else addOneBound(param, rawBound1, isUpper)
303316 else
304317
305318 // Narrow one of the bounds of type parameter `param`
@@ -730,6 +743,7 @@ trait ConstraintHandling {
730743 // (we do not check for non-toplevel occurrences: those should never occur
731744 // since `addOneBound` disallows recursive lower bounds).
732745 if constraint.occursAtToplevel(param, widened) then
746+ assert(widened ne approx, i " instance of $param = $approx in $constraint" )
733747 instanceType(param, fromBelow, widen, maxLevel)
734748 else
735749 widened
0 commit comments