@@ -81,16 +81,28 @@ trait ConstraintHandling {
8181 assert(homogenizeArgs == false)
8282 assert(comparedTypeLambdas == Set.empty)
8383
84- def nestingLevel(param: TypeParamRef) = constraint.typeVarOfParam(param) match
84+ def nestingLevel(param: TypeParamRef)(using Context) = constraint.typeVarOfParam(param) match
8585 case tv: TypeVar => tv.nestingLevel
86- case _ => Int.MaxValue
86+ case _ =>
87+ // This should only happen when reducing match types (in
88+ // TrackingTypeComparer#matchCases) or in uncommitable TyperStates (as
89+ // asserted in ProtoTypes.constrained) and is special-cased in `levelOK`
90+ // below.
91+ Int.MaxValue
92+
93+ /** Is `level` <= `maxLevel` or legal in the current context? */
94+ def levelOK(level: Int, maxLevel: Int)(using Context): Boolean =
95+ level <= maxLevel ||
96+ ctx.isAfterTyper || !ctx.typerState.isCommittable || // Leaks in these cases shouldn't break soundness
97+ level == Int.MaxValue // See `nestingLevel` above.
8798
8899 /** If `param` is nested deeper than `maxLevel`, try to instantiate it to a
89100 * fresh type variable of level `maxLevel` and return the new variable.
90101 * If this isn't possible, throw a TypeError.
91102 */
92103 def atLevel(maxLevel: Int, param: TypeParamRef)(using Context): TypeParamRef =
93- if nestingLevel(param) <= maxLevel then return param
104+ if levelOK(nestingLevel(param), maxLevel) then
105+ return param
94106 LevelAvoidMap(0, maxLevel)(param) match
95107 case freshVar: TypeVar => freshVar.origin
96108 case _ => throw new TypeError(
@@ -129,18 +141,12 @@ trait ConstraintHandling {
129141
130142 /** An approximating map that prevents types nested deeper than maxLevel as
131143 * well as WildcardTypes from leaking into the constraint.
132- * Note that level-checking is turned off after typer and in uncommitable
133- * TyperState since these leaks should be safe.
134144 */
135145 class LevelAvoidMap(topLevelVariance: Int, maxLevel: Int)(using Context) extends TypeOps.AvoidMap:
136146 variance = topLevelVariance
137147
138- /** Are we allowed to refer to types of the given `level`? */
139- private def levelOK(level: Int): Boolean =
140- level <= maxLevel || ctx.isAfterTyper || !ctx.typerState.isCommittable
141-
142148 def toAvoid(tp: NamedType): Boolean =
143- tp.prefix == NoPrefix && !tp.symbol.isStatic && !levelOK(tp.symbol.nestingLevel)
149+ tp.prefix == NoPrefix && !tp.symbol.isStatic && !levelOK(tp.symbol.nestingLevel, maxLevel )
144150
145151 /** Return a (possibly fresh) type variable of a level no greater than `maxLevel` which is:
146152 * - lower-bounded by `tp` if variance >= 0
@@ -185,7 +191,7 @@ trait ConstraintHandling {
185191 end legalVar
186192
187193 override def apply(tp: Type): Type = tp match
188- case tp: TypeVar if !tp.isInstantiated && !levelOK(tp.nestingLevel) =>
194+ case tp: TypeVar if !tp.isInstantiated && !levelOK(tp.nestingLevel, maxLevel ) =>
189195 legalVar(tp)
190196 // TypeParamRef can occur in tl bounds
191197 case tp: TypeParamRef =>
@@ -431,7 +437,6 @@ trait ConstraintHandling {
431437 final def approximation(param: TypeParamRef, fromBelow: Boolean)(using Context): Type =
432438 constraint.entry(param) match
433439 case entry: TypeBounds =>
434- val maxLevel = nestingLevel(param)
435440 val useLowerBound = fromBelow || param.occursIn(entry.hi)
436441 val inst = if useLowerBound then fullLowerBound(param) else fullUpperBound(param)
437442 typr.println(s"approx ${param.show}, from below = $fromBelow, inst = ${inst.show}")
0 commit comments