@@ -300,8 +300,8 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
300300// ---------- Updates ------------------------------------------------------------
301301
302302 /** If `inst` is a TypeBounds, make sure it does not contain toplevel
303- * references to `param`. Toplevel means: the term itself or a factor in some
304- * combination of `&` or `|` types .
303+ * references to `param` (see `Constraint#occursAtToplevel` for a definition
304+ * of "toplevel") .
305305 * Any such references are replace by `Nothing` in the lower bound and `Any`
306306 * in the upper bound.
307307 * References can be direct or indirect through instantiations of other
@@ -594,33 +594,36 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
594594// ---------- Checking -----------------------------------------------
595595
596596 def checkNonCyclic ()(implicit ctx : Context ): this .type =
597- if Config .checkConstraintsNonCyclic then domainParams.foreach(checkNonCyclic)
597+ if Config .checkConstraintsNonCyclic then
598+ domainParams.foreach { param =>
599+ val inst = entry(param)
600+ assert(! isLess(param, param),
601+ s " cyclic ordering involving $param in ${this .show}, upper = $inst" )
602+ assert(! occursAtToplevel(param, inst),
603+ s " cyclic bound for $param: ${inst.show} in ${this .show}" )
604+ }
598605 this
599606
600- private def checkNonCyclic (param : TypeParamRef )(implicit ctx : Context ): Unit =
601- assert(! isLess(param, param), i " cyclic ordering involving $param in $this, upper = ${upper(param)}" )
607+ def occursAtToplevel (param : TypeParamRef , inst : Type )(implicit ctx : Context ): Boolean =
602608
603- def recur (tp : Type )(using Context ): Unit = tp match
609+ def occurs (tp : Type )(using Context ): Boolean = tp match
604610 case tp : AndOrType =>
605- recur(tp.tp1)
606- recur(tp.tp2)
611+ occurs(tp.tp1) || occurs(tp.tp2)
607612 case tp : TypeParamRef =>
608- assert(tp ne param, i " cyclic bound for $param: ${entry(param)} in $this" )
609- entry(tp) match
610- case NoType =>
611- case TypeBounds (lo, hi) => if lo eq hi then recur(lo)
612- case inst => recur(inst)
613+ (tp eq param) || entry(tp).match
614+ case NoType => false
615+ case TypeBounds (lo, hi) => (lo eq hi) && occurs(lo)
616+ case inst => occurs(inst)
613617 case tp : TypeVar =>
614- recur (tp.underlying)
618+ occurs (tp.underlying)
615619 case TypeBounds (lo, hi) =>
616- recur(lo)
617- recur(hi)
620+ occurs(lo) || occurs(hi)
618621 case _ =>
619622 val tp1 = tp.dealias
620- if tp1 ne tp then recur (tp1)
623+ ( tp1 ne tp) && occurs (tp1)
621624
622- recur(entry(param) )
623- end checkNonCyclic
625+ occurs(inst )
626+ end occursAtToplevel
624627
625628 override def checkClosed ()(using Context ): Unit =
626629
0 commit comments