@@ -4110,18 +4110,17 @@ object Types {
41104110 *
41114111 * @param origin The parameter that's tracked by the type variable.
41124112 * @param creatorState The typer state in which the variable was created.
4113- *
4114- * `owningTree` and `owner` are used to determine whether a type-variable can be instantiated
4115- * at some given point. See `Inferencing#interpolateUndetVars`.
41164113 */
4117- final class TypeVar (private var _origin : TypeParamRef , creatorState : TyperState ) extends CachedProxyType with ValueType {
4114+ final class TypeVar private (initOrigin : TypeParamRef , creatorState : TyperState , nestingLevel : Int ) extends CachedProxyType with ValueType {
4115+
4116+ private var currentOrigin = initOrigin
41184117
4119- def origin : TypeParamRef = _origin
4118+ def origin : TypeParamRef = currentOrigin
41204119
41214120 /** Set origin to new parameter. Called if we merge two conflicting constraints.
41224121 * See OrderingConstraint#merge, OrderingConstraint#rename
41234122 */
4124- def setOrigin (p : TypeParamRef ) = _origin = p
4123+ def setOrigin (p : TypeParamRef ) = currentOrigin = p
41254124
41264125 /** The permanent instance type of the variable, or NoType is none is given yet */
41274126 private var myInst : Type = NoType
@@ -4150,6 +4149,36 @@ object Types {
41504149 /** Is the variable already instantiated? */
41514150 def isInstantiated (implicit ctx : Context ): Boolean = instanceOpt.exists
41524151
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 =
4156+ val problemSyms = new TypeAccumulator [Set [Symbol ]]:
4157+ def apply (syms : Set [Symbol ], t : Type ): Set [Symbol ] = t match
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.
4161+ if ref.symbol.maybeOwner.nestingLevel > nestingLevel =>
4162+ syms + ref.symbol
4163+ case _ =>
4164+ foldOver(syms, t)
4165+ val problems = problemSyms(Set .empty, tp)
4166+ if problems.isEmpty then tp
4167+ else
4168+ val atp = ctx.typer.avoid(tp, problems.toList)
4169+ def msg = i " Inaccessible variables captured in instantation of type variable $this. \n $tp was fixed to $atp"
4170+ typr.println(msg)
4171+ val bound = ctx.typeComparer.fullUpperBound(origin)
4172+ if ! (atp <:< bound) then
4173+ throw new TypeError (s " $msg, \n but the latter type does not conform to the upper bound $bound" )
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.
4181+
41534182 /** Instantiate variable with given type */
41544183 def instantiateWith (tp : Type )(implicit ctx : Context ): Type = {
41554184 assert(tp ne this , s " self instantiation of ${tp.show}, constraint = ${ctx.typerState.constraint.show}" )
@@ -4168,7 +4197,7 @@ object Types {
41684197 * is also a singleton type.
41694198 */
41704199 def instantiate (fromBelow : Boolean )(implicit ctx : Context ): Type =
4171- instantiateWith(ctx.typeComparer.instanceType(origin, fromBelow))
4200+ instantiateWith(avoidCaptures( ctx.typeComparer.instanceType(origin, fromBelow) ))
41724201
41734202 /** For uninstantiated type variables: Is the lower bound different from Nothing? */
41744203 def hasLowerBound (implicit ctx : Context ): Boolean =
@@ -4200,6 +4229,9 @@ object Types {
42004229 s " TypeVar( $origin$instStr) "
42014230 }
42024231 }
4232+ object TypeVar :
4233+ def apply (initOrigin : TypeParamRef , creatorState : TyperState )(using Context ) =
4234+ new TypeVar (initOrigin, creatorState, ctx.owner.nestingLevel)
42034235
42044236 type TypeVars = SimpleIdentitySet [TypeVar ]
42054237
0 commit comments