@@ -4149,10 +4149,15 @@ object Types {
41494149 /** Is the variable already instantiated? */
41504150 def isInstantiated (implicit ctx : Context ): Boolean = instanceOpt.exists
41514151
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 =
41534156 val problemSyms = new TypeAccumulator [Set [Symbol ]]:
41544157 def apply (syms : Set [Symbol ], t : Type ): Set [Symbol ] = t match
41554158 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.
41564161 if ref.symbol.maybeOwner.nestingLevel > nestingLevel =>
41574162 syms + ref.symbol
41584163 case _ =>
@@ -4162,21 +4167,26 @@ object Types {
41624167 else
41634168 val atp = ctx.typer.avoid(tp, problems.toList)
41644169 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)
41664171 val bound = ctx.typeComparer.fullUpperBound(origin)
41674172 if ! (atp <:< bound) then
41684173 throw new TypeError (s " $msg, \n but the latter type does not conform to the upper bound $bound" )
41694174 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.
41704181
41714182 /** Instantiate variable with given type */
41724183 def instantiateWith (tp : Type )(implicit ctx : Context ): Type = {
41734184 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}" )
41764186 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
41804190 }
41814191
41824192 /** Instantiate variable from the constraints over its `origin`.
@@ -4187,7 +4197,7 @@ object Types {
41874197 * is also a singleton type.
41884198 */
41894199 def instantiate (fromBelow : Boolean )(implicit ctx : Context ): Type =
4190- instantiateWith(ctx.typeComparer.instanceType(origin, fromBelow))
4200+ instantiateWith(avoidCaptures( ctx.typeComparer.instanceType(origin, fromBelow) ))
41914201
41924202 /** For uninstantiated type variables: Is the lower bound different from Nothing? */
41934203 def hasLowerBound (implicit ctx : Context ): Boolean =
0 commit comments