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