aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-09-18 17:22:14 +0200
committerMartin Odersky <odersky@gmail.com>2015-09-18 17:22:14 +0200
commit7a97e86c71090600397fd9b14a5a4111c52d8498 (patch)
treec8e13bd1ca8fce1a63ead0491c1eae9004b4e0a5
parent3a8f70881c4e2298008cadee4def9d13cebcbe12 (diff)
downloaddotty-7a97e86c71090600397fd9b14a5a4111c52d8498.tar.gz
dotty-7a97e86c71090600397fd9b14a5a4111c52d8498.tar.bz2
dotty-7a97e86c71090600397fd9b14a5a4111c52d8498.zip
Change algorithm that computes instantiation direction
Change algorithm that determines whether type variables are minimized or maximized. We used to look only at the variance type variable in the containing type. We now also look with higher precedence at the direction from which the type variable was constrained. This is closer to what scalac does.
-rw-r--r--src/dotty/tools/dotc/core/ConstraintHandling.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala52
2 files changed, 45 insertions, 9 deletions
diff --git a/src/dotty/tools/dotc/core/ConstraintHandling.scala b/src/dotty/tools/dotc/core/ConstraintHandling.scala
index 544304e8a..6f0377a4d 100644
--- a/src/dotty/tools/dotc/core/ConstraintHandling.scala
+++ b/src/dotty/tools/dotc/core/ConstraintHandling.scala
@@ -104,7 +104,7 @@ trait ConstraintHandling {
up.forall(addOneBound(_, lo, isUpper = false))
}
- protected final def isSubTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
+ final def isSubTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
val saved = frozenConstraint
frozenConstraint = true
try isSubType(tp1, tp2)
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index 8df544dd6..6c8bf49ef 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -44,8 +44,20 @@ trait Inferencing { this: Checking =>
else throw new Error(i"internal error: type of $what $tp is not fully defined, pos = $pos") // !!! DEBUG
/** The accumulator which forces type variables using the policy encoded in `force`
- * and returns whether the type is fully defined. Two phases:
- * 1st Phase: Try to instantiate covariant and non-variant type variables to
+ * and returns whether the type is fully defined. The direction in which
+ * a type variable is instantiated is determined as follows:
+ * 1. T is minimized if the constraint over T is only from below (i.e.
+ * constrained lower bound != given lower bound and
+ * constrained upper bound == given upper bound).
+ * 2. T is maximized if the constraint over T is only from above (i.e.
+ * constrained upper bound != given upper bound and
+ * constrained lower bound == given lower bound).
+ * If (1) and (2) do not apply:
+ * 3. T is maximized if it appears only contravariantly in the given type.
+ * 4. T is minimized in all other cases.
+ *
+ * The instantiation is done in two phases:
+ * 1st Phase: Try to instantiate minimizable type variables to
* their lower bound. Record whether successful.
* 2nd Phase: If first phase was successful, instantiate all remaining type variables
* to their upper bound.
@@ -63,12 +75,19 @@ trait Inferencing { this: Checking =>
case tvar: TypeVar if !tvar.isInstantiated =>
if (force == ForceDegree.none) false
else {
- val minimize =
- variance >= 0 && !(
- force == ForceDegree.noBottom &&
- isBottomType(ctx.typeComparer.approximation(tvar.origin, fromBelow = true)))
- if (minimize) instantiate(tvar, fromBelow = true)
- else toMaximize = true
+ val direction = instDirection(tvar.origin)
+ if (direction != 0) {
+ if (direction > 0) println(s"inst $tvar dir = up")
+ instantiate(tvar, direction < 0)
+ }
+ else {
+ val minimize =
+ variance >= 0 && !(
+ force == ForceDegree.noBottom &&
+ isBottomType(ctx.typeComparer.approximation(tvar.origin, fromBelow = true)))
+ if (minimize) instantiate(tvar, fromBelow = true)
+ else toMaximize = true
+ }
foldOver(x, tvar)
}
case tp =>
@@ -93,6 +112,23 @@ trait Inferencing { this: Checking =>
}
}
+ /** The instantiation direction for given poly param computed
+ * from the constraint:
+ * @return 1 (maximize) if constraint is uniformly from above,
+ * -1 (minimize) if constraint is uniformly from below,
+ * 0 if unconstrained, or constraint is from below and above.
+ */
+ private def instDirection(param: PolyParam)(implicit ctx: Context): Int = {
+ val constrained = ctx.typerState.constraint.fullBounds(param)
+ val original = param.binder.paramBounds(param.paramNum)
+ val cmp = ctx.typeComparer
+ val approxBelow =
+ if (!cmp.isSubTypeWhenFrozen(constrained.lo, original.lo)) 1 else 0
+ val approxAbove =
+ if (!cmp.isSubTypeWhenFrozen(original.hi, constrained.hi)) 1 else 0
+ approxAbove - approxBelow
+ }
+
def isBottomType(tp: Type)(implicit ctx: Context) =
tp == defn.NothingType || tp == defn.NullType