@@ -463,14 +463,30 @@ trait ConstraintHandling {
463463 }
464464 }
465465
466+ /** Fix instance type `tp` by avoidance so that it does not contain references
467+ * to types at level > `maxLevel`.
468+ * @param tp the type to be fixed
469+ * @param fromBelow whether type was obtained from lower bound
470+ * @param maxLevel the maximum level of references allowed
471+ * @param param the parameter that was instantiated
472+ */
466473 private def fixLevels (tp : Type , fromBelow : Boolean , maxLevel : Int , param : TypeParamRef )(using Context ) =
467474
468475 def needsFix (tp : NamedType ) =
469476 (tp.prefix eq NoPrefix ) && tp.symbol.nestingLevel > maxLevel
470477
478+ /** An accumulator that determines whether levels need to be fixed
479+ * and computes on the side sets of nested type variables that need
480+ * to be instantiated.
481+ */
471482 class NeedsLeveling extends TypeAccumulator [Boolean ]:
472483 if ! fromBelow then variance = - 1
484+
485+ /** Nested type variables that should be instiated to theor lower (respoctively
486+ * upper) bounds.
487+ */
473488 var nestedVarsLo, nestedVarsHi : SimpleIdentitySet [TypeVar ] = SimpleIdentitySet .empty
489+
474490 def apply (need : Boolean , tp : Type ) =
475491 need || tp.match
476492 case tp : NamedType =>
@@ -483,17 +499,24 @@ trait ConstraintHandling {
483499 if variance > 0 then nestedVarsLo += tp
484500 else if variance < 0 then nestedVarsHi += tp
485501 else tp.nestingLevel = maxLevel
502+ // For invariant type variables, we use a different strategy.
503+ // Rather than instantiating to a bound and then propagating in an
504+ // AvoidMap, change the nesting level of an invariant type
505+ // variable to `maxLevel`. This means that the type variable will be
506+ // instantiated later to a less nested type. If there are other references
507+ // to the same type variable that do not come from the type undergoing
508+ // `fixLevels`, this could lead to coarser types. But it has the potential
509+ // to give a better approximation for the current type, since it avoids forming
510+ // a Range in invariant position, which can lead to very coarse types further out.
486511 true
487512 else false
488513 case _ =>
489514 foldOver(need, tp)
515+ end NeedsLeveling
490516
491517 class LevelAvoidMap extends TypeOps .AvoidMap :
492518 if ! fromBelow then variance = - 1
493519 def toAvoid (tp : NamedType ) = needsFix(tp)
494- // override def apply(tp: Type): Type = tp match
495- // case tp: LazyRef => tp
496- // case _ => super.apply(tp)
497520
498521 if ctx.isAfterTyper then tp
499522 else
@@ -512,6 +535,8 @@ trait ConstraintHandling {
512535 * contains a reference to the parameter itself (such occurrences can arise
513536 * for F-bounded types, `addOneBound` ensures that they never occur in the
514537 * lower bound).
538+ * The solved type is not allowed to contain references to types nested deeper
539+ * than `maxLevel`.
515540 * Wildcard types in bounds are approximated by their upper or lower bounds.
516541 * The constraint is left unchanged.
517542 * @return the instantiating type
@@ -639,6 +664,8 @@ trait ConstraintHandling {
639664 * lower bounds; otherwise it is the glb of its upper bounds. However,
640665 * a lower bound instantiation can be a singleton type only if the upper bound
641666 * is also a singleton type.
667+ * The instance type is not allowed to contain references to types nested deeper
668+ * than `maxLevel`.
642669 */
643670 def instanceType (param : TypeParamRef , fromBelow : Boolean , maxLevel : Int )(using Context ): Type = {
644671 val approx = approximation(param, fromBelow, maxLevel).simplified
0 commit comments