@@ -20,6 +20,7 @@ import config.Printers.{typr, constr}
20
20
import annotation .tailrec
21
21
import reporting ._
22
22
import collection .mutable
23
+ import config .Config
23
24
24
25
object Inferencing {
25
26
@@ -161,12 +162,16 @@ object Inferencing {
161
162
* - The prefix `p` of a selection `p.f`.
162
163
* - The result expression `e` of a block `{s1; .. sn; e}`.
163
164
*/
164
- def tvarsInParams (tree : Tree )(implicit ctx : Context ): List [TypeVar ] = {
165
+ def tvarsInParams (tree : Tree , locked : TypeVars )(implicit ctx : Context ): List [TypeVar ] = {
165
166
@ tailrec def boundVars (tree : Tree , acc : List [TypeVar ]): List [TypeVar ] = tree match {
166
167
case Apply (fn, _) => boundVars(fn, acc)
167
168
case TypeApply (fn, targs) =>
168
169
val tvars = targs.tpes.collect {
169
- case tvar : TypeVar if ! tvar.isInstantiated && targs.contains(tvar.bindingTree) => tvar
170
+ case tvar : TypeVar
171
+ if ! tvar.isInstantiated &&
172
+ targs.contains(tvar.bindingTree) &&
173
+ ctx.typerState.ownedVars.contains(tvar) &&
174
+ ! locked.contains(tvar) => tvar
170
175
}
171
176
boundVars(fn, acc ::: tvars)
172
177
case Select (pre, _) => boundVars(pre, acc)
@@ -228,7 +233,7 @@ object Inferencing {
228
233
* to instantiate undetermined type variables that occur non-variantly
229
234
*/
230
235
def maximizeType (tp : Type , pos : Position , fromScala2x : Boolean )(implicit ctx : Context ): List [Symbol ] = Stats .track(" maximizeType" ) {
231
- val vs = variances(tp, alwaysTrue )
236
+ val vs = variances(tp)
232
237
val patternBound = new mutable.ListBuffer [Symbol ]
233
238
vs foreachBinding { (tvar, v) =>
234
239
if (v == 1 ) tvar.instantiate(fromBelow = false )
@@ -265,14 +270,14 @@ object Inferencing {
265
270
*
266
271
* we want to instantiate U to x.type right away. No need to wait further.
267
272
*/
268
- private def variances (tp : Type , include : TypeVar => Boolean )(implicit ctx : Context ): VarianceMap = Stats .track(" variances" ) {
273
+ private def variances (tp : Type )(implicit ctx : Context ): VarianceMap = Stats .track(" variances" ) {
269
274
val constraint = ctx.typerState.constraint
270
275
271
276
object accu extends TypeAccumulator [VarianceMap ] {
272
277
def setVariance (v : Int ) = variance = v
273
278
def apply (vmap : VarianceMap , t : Type ): VarianceMap = t match {
274
279
case t : TypeVar
275
- if ! t.isInstantiated && ( ctx.typerState.constraint contains t) && include (t) =>
280
+ if ! t.isInstantiated && ctx.typerState.constraint. contains(t) =>
276
281
val v = vmap(t)
277
282
if (v == null ) vmap.updated(t, variance)
278
283
else if (v == variance || v == 0 ) vmap
@@ -319,42 +324,41 @@ trait Inferencing { this: Typer =>
319
324
import Inferencing ._
320
325
import tpd ._
321
326
322
- /** Interpolate those undetermined type variables in the widened type of this tree
323
- * which are introduced by type application contained in the tree.
324
- * If such a variable appears covariantly in type `tp` or does not appear at all,
325
- * approximate it by its lower bound. Otherwise, if it appears contravariantly
326
- * in type `tp` approximate it by its upper bound.
327
- * @param ownedBy if it is different from NoSymbol, all type variables owned by
328
- * `ownedBy` qualify, independent of position.
329
- * Without that second condition, it can be that certain variables escape
330
- * interpolation, for instance when their tree was eta-lifted, so
331
- * the typechecked tree is no longer the tree in which the variable
332
- * was declared. A concrete example of this phenomenon can be
333
- * observed when compiling core.TypeOps#asSeenFrom.
327
+ /** Interpolate undetermined type variables in the widened type of this tree.
328
+ * @param tree the tree whose type is interpolated
329
+ * @param pt the expected result type
330
+ * @param locked the set of type variables of the current typer state that cannot be interpolated
331
+ * at the present time
332
+ * Eligible for interpolation are all type variables owned by the current typerstate
333
+ * that are not in locked. Type variables occurring co- (respectively, contra-) variantly in the type
334
+ * are minimized (respectvely, maximized). Non occurring type variables are minimized if they
335
+ * have a lower bound different from Nothing, maximized otherwise. Type variables appearing
336
+ * non-variantly in the type are left untouched.
337
+ *
338
+ * Note that even type variables that do not appear directly in a type, can occur with
339
+ * some variance in the type, because of the constraints. E.g if `X` occurs co-variantly in `T`
340
+ * and we have a constraint
341
+ *
342
+ * Y <: X
343
+ *
344
+ * Then `Y` also occurs co-variantly in `T` because it needs to be minimized in order to constrain
345
+ * `T` teh least. See `variances` for more detail.
334
346
*/
335
- def interpolateUndetVars (tree : Tree , ownedBy : Symbol , pt : Type )(implicit ctx : Context ): Unit = {
336
- val constraint = ctx.typerState.constraint
337
- val qualifies = (tvar : TypeVar ) =>
338
- (tree contains tvar.bindingTree) || ownedBy.exists && tvar.owner == ownedBy
339
- def interpolate () = Stats .track(" interpolateUndetVars" ) {
340
- val tp = tree.tpe.widen
341
- constr.println(s " interpolate undet vars in ${tp.show}, pos = ${tree.pos}, mode = ${ctx.mode}, undets = ${constraint.uninstVars map (tvar => s " ${tvar.show}@ ${tvar.bindingTree.pos}" )}" )
342
- constr.println(s " qualifying undet vars: ${constraint.uninstVars filter qualifies map (tvar => s " $tvar / ${tvar.show}" )}, constraint: ${constraint.show}" )
343
-
344
- val vs = variances(tp, qualifies)
345
- val hasUnreportedErrors = ctx.typerState.reporter match {
346
- case r : StoreReporter if r.hasErrors => true
347
- case _ => false
348
- }
349
-
350
- var isConstrained = tree.isInstanceOf [Apply ] || tree.tpe.isInstanceOf [MethodOrPoly ]
351
-
352
- def ensureConstrained () = if (! isConstrained) {
353
- isConstrained = true
347
+ def interpolateTypeVars (tree : Tree , pt : Type , locked : TypeVars )(implicit ctx : Context ): tree.type = {
348
+ val state = ctx.typerState
349
+ if (state.ownedVars.size > locked.size) {
350
+ val qualifying = state.ownedVars -- locked
351
+ typr.println(i " interpolate $tree: ${tree.tpe.widen} in $state, owned vars = ${state.ownedVars.toList}%, %, previous = ${locked.toList}%, % / ${state.constraint}" )
352
+ val resultAlreadyConstrained =
353
+ tree.isInstanceOf [Apply ] || tree.tpe.isInstanceOf [MethodOrPoly ]
354
+ if (! resultAlreadyConstrained)
354
355
constrainResult(tree.tpe, pt)
355
- }
356
+ // This is needed because it could establish singleton type upper bounds. See i2998.scala.
356
357
357
- // Avoid interpolating variables if typerstate has unreported errors.
358
+ val tp = tree.tpe.widen
359
+ val vs = variances(tp)
360
+
361
+ // Avoid interpolating variables occurring in tree's type if typerstate has unreported errors.
358
362
// Reason: The errors might reflect unsatisfiable constraints. In that
359
363
// case interpolating without taking account the constraints risks producing
360
364
// nonsensical types that then in turn produce incomprehensible errors.
@@ -374,39 +378,29 @@ trait Inferencing { this: Typer =>
374
378
// found : Int(1)
375
379
// required: String
376
380
// val y: List[List[String]] = List(List(1))
377
- if (! hasUnreportedErrors)
378
- vs foreachBinding { (tvar, v) =>
379
- if (v != 0 && ctx.typerState.constraint.contains(tvar)) {
380
- // previous interpolations could have already instantiated `tvar`
381
- // through unification, that's why we have to check again whether `tvar`
382
- // is contained in the current constraint.
383
- typr.println(s " interpolate ${if (v == 1 ) " co" else " contra" }variant ${tvar.show} in ${tp.show}" )
384
- ensureConstrained()
385
- tvar.instantiate(fromBelow = v == 1 )
381
+ val hasUnreportedErrors = state.reporter match {
382
+ case r : StoreReporter if r.hasErrors => true
383
+ case _ => false
384
+ }
385
+ def constraint = state.constraint
386
+ for (tvar <- qualifying)
387
+ if (! tvar.isInstantiated && state.constraint.contains(tvar)) {
388
+ // Needs to be checked again, since previous interpolations could already have
389
+ // instantiated `tvar` through unification.
390
+ val v = vs(tvar)
391
+ if (v == null ) {
392
+ typr.println(i " interpolate non-occurring $tvar in $state in $tree: $tp, fromBelow = ${tvar.hasLowerBound}, $constraint" )
393
+ tvar.instantiate(fromBelow = tvar.hasLowerBound)
386
394
}
395
+ else if (! hasUnreportedErrors)
396
+ if (v.intValue != 0 ) {
397
+ typr.println(i " interpolate $tvar in $state in $tree: $tp, fromBelow = ${v.intValue == 1 }, $constraint" )
398
+ tvar.instantiate(fromBelow = v.intValue == 1 )
399
+ }
400
+ else typr.println(i " no interpolation for nonvariant $tvar in $state" )
387
401
}
388
- for (tvar <- constraint.uninstVars)
389
- if (! (vs contains tvar) && qualifies(tvar)) {
390
- typr.println(s " instantiating non-occurring ${tvar.show} in ${tp.show} / $tp" )
391
- ensureConstrained()
392
- tvar.instantiate(fromBelow = tvar.hasLowerBound)
393
- }
394
- }
395
- if (constraint.uninstVars exists qualifies) interpolate()
396
- }
397
-
398
- /** The uninstantiated type variables introduced somehwere in `tree` */
399
- def uninstBoundVars (tree : Tree )(implicit ctx : Context ): List [TypeVar ] = {
400
- val buf = new mutable.ListBuffer [TypeVar ]
401
- tree.foreachSubTree {
402
- case TypeApply (_, args) =>
403
- args.tpes.foreach {
404
- case tv : TypeVar if ! tv.isInstantiated && tree.contains(tv.bindingTree) => buf += tv
405
- case _ =>
406
- }
407
- case _ =>
408
402
}
409
- buf.toList
403
+ tree
410
404
}
411
405
}
412
406
0 commit comments