@@ -463,14 +463,30 @@ trait ConstraintHandling {
463
463
}
464
464
}
465
465
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
+ */
466
473
private def fixLevels (tp : Type , fromBelow : Boolean , maxLevel : Int , param : TypeParamRef )(using Context ) =
467
474
468
475
def needsFix (tp : NamedType ) =
469
476
(tp.prefix eq NoPrefix ) && tp.symbol.nestingLevel > maxLevel
470
477
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
+ */
471
482
class NeedsLeveling extends TypeAccumulator [Boolean ]:
472
483
if ! fromBelow then variance = - 1
484
+
485
+ /** Nested type variables that should be instiated to theor lower (respoctively
486
+ * upper) bounds.
487
+ */
473
488
var nestedVarsLo, nestedVarsHi : SimpleIdentitySet [TypeVar ] = SimpleIdentitySet .empty
489
+
474
490
def apply (need : Boolean , tp : Type ) =
475
491
need || tp.match
476
492
case tp : NamedType =>
@@ -483,17 +499,24 @@ trait ConstraintHandling {
483
499
if variance > 0 then nestedVarsLo += tp
484
500
else if variance < 0 then nestedVarsHi += tp
485
501
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.
486
511
true
487
512
else false
488
513
case _ =>
489
514
foldOver(need, tp)
515
+ end NeedsLeveling
490
516
491
517
class LevelAvoidMap extends TypeOps .AvoidMap :
492
518
if ! fromBelow then variance = - 1
493
519
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)
497
520
498
521
if ctx.isAfterTyper then tp
499
522
else
@@ -512,6 +535,8 @@ trait ConstraintHandling {
512
535
* contains a reference to the parameter itself (such occurrences can arise
513
536
* for F-bounded types, `addOneBound` ensures that they never occur in the
514
537
* lower bound).
538
+ * The solved type is not allowed to contain references to types nested deeper
539
+ * than `maxLevel`.
515
540
* Wildcard types in bounds are approximated by their upper or lower bounds.
516
541
* The constraint is left unchanged.
517
542
* @return the instantiating type
@@ -639,6 +664,8 @@ trait ConstraintHandling {
639
664
* lower bounds; otherwise it is the glb of its upper bounds. However,
640
665
* a lower bound instantiation can be a singleton type only if the upper bound
641
666
* is also a singleton type.
667
+ * The instance type is not allowed to contain references to types nested deeper
668
+ * than `maxLevel`.
642
669
*/
643
670
def instanceType (param : TypeParamRef , fromBelow : Boolean , maxLevel : Int )(using Context ): Type = {
644
671
val approx = approximation(param, fromBelow, maxLevel).simplified
0 commit comments