@@ -4149,10 +4149,15 @@ object Types {
4149
4149
/** Is the variable already instantiated? */
4150
4150
def isInstantiated (implicit ctx : Context ): Boolean = instanceOpt.exists
4151
4151
4152
- def avoidCaptures (tp : Type )(using Context ): Type =
4152
+ /** Avoid term references in `tp` to parameters or local variables that
4153
+ * are nested more deeply than the type variable itself.
4154
+ */
4155
+ private def avoidCaptures (tp : Type )(using Context ): Type =
4153
4156
val problemSyms = new TypeAccumulator [Set [Symbol ]]:
4154
4157
def apply (syms : Set [Symbol ], t : Type ): Set [Symbol ] = t match
4155
4158
case ref @ TermRef (NoPrefix , _)
4159
+ // AVOIDANCE TODO: Are there other problematic kinds of references?
4160
+ // Our current tests only give us these, but we might need to generalize this.
4156
4161
if ref.symbol.maybeOwner.nestingLevel > nestingLevel =>
4157
4162
syms + ref.symbol
4158
4163
case _ =>
@@ -4162,21 +4167,26 @@ object Types {
4162
4167
else
4163
4168
val atp = ctx.typer.avoid(tp, problems.toList)
4164
4169
val msg = i " Inaccessible variables captured in instantation of type variable $this. \n $tp was fixed to $atp"
4165
- typr. println(msg)
4170
+ println(msg)
4166
4171
val bound = ctx.typeComparer.fullUpperBound(origin)
4167
4172
if ! (atp <:< bound) then
4168
4173
throw new TypeError (s " $msg, \n but the latter type does not conform to the upper bound $bound" )
4169
4174
atp
4175
+ // AVOIDANCE TODO: This really works well only if variables are instantiated from below
4176
+ // If we hit a problematic symbol while instantiating from above, then avoidance
4177
+ // will widen the instance type further. This could yield an alias, which would be OK.
4178
+ // But it also could yield a true super type which would then fail the bounds check
4179
+ // and throw a TypeError. The right thing to do instead would be to avoid "downwards".
4180
+ // To do this, we need first test cases for that situation.
4170
4181
4171
4182
/** Instantiate variable with given type */
4172
4183
def instantiateWith (tp : Type )(implicit ctx : Context ): Type = {
4173
4184
assert(tp ne this , s " self instantiation of ${tp.show}, constraint = ${ctx.typerState.constraint.show}" )
4174
- val atp = avoidCaptures(tp)
4175
- typr.println(s " instantiating ${this .show} with ${atp.show}" )
4185
+ typr.println(s " instantiating ${this .show} with ${tp.show}" )
4176
4186
if ((ctx.typerState eq owningState.get) && ! ctx.typeComparer.subtypeCheckInProgress)
4177
- inst = atp
4178
- ctx.typerState.constraint = ctx.typerState.constraint.replace(origin, atp )
4179
- atp
4187
+ inst = tp
4188
+ ctx.typerState.constraint = ctx.typerState.constraint.replace(origin, tp )
4189
+ tp
4180
4190
}
4181
4191
4182
4192
/** Instantiate variable from the constraints over its `origin`.
@@ -4187,7 +4197,7 @@ object Types {
4187
4197
* is also a singleton type.
4188
4198
*/
4189
4199
def instantiate (fromBelow : Boolean )(implicit ctx : Context ): Type =
4190
- instantiateWith(ctx.typeComparer.instanceType(origin, fromBelow))
4200
+ instantiateWith(avoidCaptures( ctx.typeComparer.instanceType(origin, fromBelow) ))
4191
4201
4192
4202
/** For uninstantiated type variables: Is the lower bound different from Nothing? */
4193
4203
def hasLowerBound (implicit ctx : Context ): Boolean =
0 commit comments