@@ -396,6 +396,87 @@ trait Inferencing { this: Typer =>
396
396
}
397
397
}
398
398
399
+ trait Inferencing { this : Typer =>
400
+ import Inferencing ._
401
+ import tpd ._
402
+
403
+ /** Interpolate those undetermined type variables in the widened type of this tree
404
+ * which are introduced by type application contained in the tree.
405
+ * If such a variable appears covariantly in type `tp` or does not appear at all,
406
+ * approximate it by its lower bound. Otherwise, if it appears contravariantly
407
+ * in type `tp` approximate it by its upper bound.
408
+ * @param ownedBy if it is different from NoSymbol, all type variables owned by
409
+ * `ownedBy` qualify, independent of position.
410
+ * Without that second condition, it can be that certain variables escape
411
+ * interpolation, for instance when their tree was eta-lifted, so
412
+ * the typechecked tree is no longer the tree in which the variable
413
+ * was declared. A concrete example of this phenomenon can be
414
+ * observed when compiling core.TypeOps#asSeenFrom.
415
+ */
416
+ def interpolateUndetVars (tree : Tree , ownedBy : Symbol , pt : Type )(implicit ctx : Context ): Unit = {
417
+ val constraint = ctx.typerState.constraint
418
+ val qualifies = (tvar : TypeVar ) =>
419
+ (tree contains tvar.bindingTree) || ownedBy.exists && tvar.owner == ownedBy
420
+ def interpolate () = Stats .track(" interpolateUndetVars" ) {
421
+ val tp = tree.tpe.widen
422
+ 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}" )}" )
423
+ constr.println(s " qualifying undet vars: ${constraint.uninstVars filter qualifies map (tvar => s " $tvar / ${tvar.show}" )}, constraint: ${constraint.show}" )
424
+
425
+ val vs = variances(tp, qualifies)
426
+ val hasUnreportedErrors = ctx.typerState.reporter match {
427
+ case r : StoreReporter if r.hasErrors => true
428
+ case _ => false
429
+ }
430
+
431
+ var isConstrained = tree.isInstanceOf [Apply ] || tree.tpe.isInstanceOf [MethodOrPoly ]
432
+
433
+ def ensureConstrained () = if (! isConstrained) {
434
+ isConstrained = true
435
+ constrainResult(tree.tpe, pt)
436
+ }
437
+
438
+ // Avoid interpolating variables if typerstate has unreported errors.
439
+ // Reason: The errors might reflect unsatisfiable constraints. In that
440
+ // case interpolating without taking account the constraints risks producing
441
+ // nonsensical types that then in turn produce incomprehensible errors.
442
+ // An example is in neg/i1240.scala. Without the condition in the next code line
443
+ // we get for
444
+ //
445
+ // val y: List[List[String]] = List(List(1))
446
+ //
447
+ // i1430.scala:5: error: type mismatch:
448
+ // found : Int(1)
449
+ // required: Nothing
450
+ // val y: List[List[String]] = List(List(1))
451
+ // ^
452
+ // With the condition, we get the much more sensical:
453
+ //
454
+ // i1430.scala:5: error: type mismatch:
455
+ // found : Int(1)
456
+ // required: String
457
+ // val y: List[List[String]] = List(List(1))
458
+ if (! hasUnreportedErrors)
459
+ vs foreachBinding { (tvar, v) =>
460
+ if (v != 0 && ctx.typerState.constraint.contains(tvar)) {
461
+ // previous interpolations could have already instantiated `tvar`
462
+ // through unification, that's why we have to check again whether `tvar`
463
+ // is contained in the current constraint.
464
+ typr.println(s " interpolate ${if (v == 1 ) " co" else " contra" }variant ${tvar.show} in ${tp.show}" )
465
+ ensureConstrained()
466
+ tvar.instantiate(fromBelow = v == 1 )
467
+ }
468
+ }
469
+ for (tvar <- constraint.uninstVars)
470
+ if (! (vs contains tvar) && qualifies(tvar)) {
471
+ typr.println(s " instantiating non-occurring ${tvar.show} in ${tp.show} / $tp" )
472
+ ensureConstrained()
473
+ tvar.instantiate(fromBelow = true )
474
+ }
475
+ }
476
+ if (constraint.uninstVars exists qualifies) interpolate()
477
+ }
478
+ }
479
+
399
480
/** An enumeration controlling the degree of forcing in "is-dully-defined" checks. */
400
481
@ sharable object ForceDegree {
401
482
class Value (val appliesTo : TypeVar => Boolean , val minimizeAll : Boolean )
0 commit comments