diff options
author | Martin Odersky <odersky@gmail.com> | 2015-09-18 17:22:14 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2015-09-18 17:22:14 +0200 |
commit | 7a97e86c71090600397fd9b14a5a4111c52d8498 (patch) | |
tree | c8e13bd1ca8fce1a63ead0491c1eae9004b4e0a5 | |
parent | 3a8f70881c4e2298008cadee4def9d13cebcbe12 (diff) | |
download | dotty-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.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Inferencing.scala | 52 |
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 |