Skip to content

Commit be6d565

Browse files
committed
Cleanup commit
This commit cleans up a piece of code of scala#3774 (which is already merged). It was suggested in review comments.
1 parent 466bcf1 commit be6d565

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

compiler/src/dotty/tools/dotc/typer/Inferencing.scala

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,87 @@ trait Inferencing { this: Typer =>
396396
}
397397
}
398398

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+
399480
/** An enumeration controlling the degree of forcing in "is-dully-defined" checks. */
400481
@sharable object ForceDegree {
401482
class Value(val appliesTo: TypeVar => Boolean, val minimizeAll: Boolean)

0 commit comments

Comments
 (0)