@@ -81,16 +81,28 @@ trait ConstraintHandling {
81
81
assert(homogenizeArgs == false )
82
82
assert(comparedTypeLambdas == Set .empty)
83
83
84
- def nestingLevel (param : TypeParamRef ) = constraint.typeVarOfParam(param) match
84
+ def nestingLevel (param : TypeParamRef )( using Context ) = constraint.typeVarOfParam(param) match
85
85
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.
87
98
88
99
/** If `param` is nested deeper than `maxLevel`, try to instantiate it to a
89
100
* fresh type variable of level `maxLevel` and return the new variable.
90
101
* If this isn't possible, throw a TypeError.
91
102
*/
92
103
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
94
106
LevelAvoidMap (0 , maxLevel)(param) match
95
107
case freshVar : TypeVar => freshVar.origin
96
108
case _ => throw new TypeError (
@@ -129,18 +141,12 @@ trait ConstraintHandling {
129
141
130
142
/** An approximating map that prevents types nested deeper than maxLevel as
131
143
* 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.
134
144
*/
135
145
class LevelAvoidMap (topLevelVariance : Int , maxLevel : Int )(using Context ) extends TypeOps .AvoidMap :
136
146
variance = topLevelVariance
137
147
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
-
142
148
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 )
144
150
145
151
/** Return a (possibly fresh) type variable of a level no greater than `maxLevel` which is:
146
152
* - lower-bounded by `tp` if variance >= 0
@@ -185,7 +191,7 @@ trait ConstraintHandling {
185
191
end legalVar
186
192
187
193
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 ) =>
189
195
legalVar(tp)
190
196
// TypeParamRef can occur in tl bounds
191
197
case tp : TypeParamRef =>
@@ -431,7 +437,6 @@ trait ConstraintHandling {
431
437
final def approximation (param : TypeParamRef , fromBelow : Boolean )(using Context ): Type =
432
438
constraint.entry(param) match
433
439
case entry : TypeBounds =>
434
- val maxLevel = nestingLevel(param)
435
440
val useLowerBound = fromBelow || param.occursIn(entry.hi)
436
441
val inst = if useLowerBound then fullLowerBound(param) else fullUpperBound(param)
437
442
typr.println(s " approx ${param.show}, from below = $fromBelow, inst = ${inst.show}" )
0 commit comments