aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/typer/Inferencing.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-01-13 09:26:52 +0100
committerMartin Odersky <odersky@gmail.com>2014-01-13 09:26:52 +0100
commit0ce813b1887348c148faa0525f4053227913014e (patch)
treee19f7ea2be71da5cdfa09a638d32162a710ff45f /src/dotty/tools/dotc/typer/Inferencing.scala
parent6b83b526cd3c9e0ce2931bd9b999b67ea230a705 (diff)
downloaddotty-0ce813b1887348c148faa0525f4053227913014e.tar.gz
dotty-0ce813b1887348c148faa0525f4053227913014e.tar.bz2
dotty-0ce813b1887348c148faa0525f4053227913014e.zip
Redo isFullyDefinedAccumulator
The new scheme is robust even when following freshky instantiated type variables. These did not show up in the old varianceMap scheme.
Diffstat (limited to 'src/dotty/tools/dotc/typer/Inferencing.scala')
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala65
1 files changed, 43 insertions, 22 deletions
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index 570eabc8d..85790094c 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -244,7 +244,7 @@ object Inferencing {
*/
def isFullyDefined(tp: Type, force: ForceDegree.Value)(implicit ctx: Context): Boolean = {
val nestedCtx = ctx.fresh.withNewTyperState
- val result = new IsFullyDefinedAccumulator(force)(nestedCtx).traverse(tp)
+ val result = new IsFullyDefinedAccumulator(force)(nestedCtx).process(tp)
if (result) nestedCtx.typerState.commit()
result
}
@@ -256,39 +256,60 @@ object Inferencing {
if (isFullyDefined(tp, ForceDegree.all)) tp
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 stantiate covariant and non-variant type variables to
+ * their lower bound. Record whether succesful.
+ * 2nd Phase: If first phase was succesful, instantiate all remaining type variables
+ * to their upper bound.
+ */
private class IsFullyDefinedAccumulator(force: ForceDegree.Value)(implicit ctx: Context) extends TypeAccumulator[Boolean] {
- private var vs: SimpleMap[TypeVar, Integer] = null
- private var rootTp: Type = null
- def isContravariant(tvar: TypeVar) = {
- (variance < 0) && { // otherwise no need to compute, it can't be contravariant
- if (vs == null) vs = rootTp.variances(alwaysTrue)
- vs(tvar) < 0
- }
- }
- def traverse(tp: Type): Boolean = {
- rootTp = tp
- apply(true, tp)
+ private def instantiate(tvar: TypeVar, fromBelow: Boolean): Type = {
+ val inst = tvar.instantiate(fromBelow)
+ typr.println(i"forced instantiation of ${tvar.origin} = $inst")
+ inst
}
- def apply(x: Boolean, tp: Type) = !x || isOK(tp) && foldOver(x, tp)
- def isOK(tp: Type): Boolean = tp match {
+ private var toMaximize: Boolean = false
+ def apply(x: Boolean, tp: Type) = x && isOK(tp) && foldOver(x, tp)
+ private def isOK(tp: Type): Boolean = tp match {
case _: WildcardType =>
false
case tvar: TypeVar if !tvar.isInstantiated =>
- def isBottomType(tp: Type) = tp == defn.NothingType || tp == defn.NullType
- force != ForceDegree.none && {
- val forceUp =
- isContravariant(tvar) ||
+ if (force == ForceDegree.none) false
+ else {
+ val minimize =
+ variance >= 0 && !(
force == ForceDegree.noBottom &&
- isBottomType(ctx.typeComparer.approximation(tvar.origin, fromBelow = true))
- val inst = tvar.instantiate(fromBelow = !forceUp)
- typr.println(i"forced instantiation of ${tvar.origin} = $inst")
- traverse(inst)
+ isBottomType(ctx.typeComparer.approximation(tvar.origin, fromBelow = true)))
+ if (minimize) instantiate(tvar, fromBelow = true)
+ else toMaximize = true
+ true
}
case _ =>
true
}
+
+ private class UpperInstantiator(implicit ctx: Context) extends TypeAccumulator[Unit] {
+ def apply(x: Unit, tp: Type): Unit = {
+ tp match {
+ case tvar: TypeVar if !tvar.isInstantiated =>
+ instantiate(tvar, fromBelow = false)
+ case _ =>
+ }
+ foldOver(x, tp)
+ }
+ }
+
+ def process(tp: Type): Boolean = {
+ val res = apply(true, tp)
+ if (res && toMaximize) new UpperInstantiator().apply((), tp)
+ res
+ }
}
+ def isBottomType(tp: Type)(implicit ctx: Context) =
+ tp == defn.NothingType || tp == defn.NullType
+
/** Recursively widen and also follow type declarations and type aliases. */
def widenForMatchSelector(tp: Type)(implicit ctx: Context): Type = tp.widen match {
case tp: TypeRef if !tp.symbol.isClass => widenForMatchSelector(tp.info.bounds.hi)