From 2985d1806b66d4bf59807f35a6427b81ef66961e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 6 Aug 2013 12:48:28 +0200 Subject: Refined treatment of unapply --- src/dotty/tools/dotc/core/Types.scala | 52 +++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-) (limited to 'src/dotty/tools/dotc/core/Types.scala') diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 07f3f284f..ff0f2e990 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -940,6 +940,31 @@ object Types { */ def varianceOf(tp: Type): FlagSet = ??? + type VarianceMap = Map[TypeVar, Int] + + /** All occurrences of type vars in this type that satisfy predicate + * `include` mapped to their variances (-1/0/1) in this type, where + * -1 means: only covariant occurrences + * +1 means: only covariant occurrences + * 0 means: mixed or non-variant occurrences + */ + def variances(include: TypeVar => Boolean)(implicit ctx: Context): VarianceMap = { + val accu = new TypeAccumulator[VarianceMap] { + def apply(vmap: VarianceMap, t: Type): VarianceMap = t match { + case t: TypeVar if include(t) => + vmap get t match { + case Some(v) => + if (v == variance) vmap else vmap updated (t, 0) + case None => + vmap updated (t, variance) + } + case _ => + foldOver(vmap, t) + } + } + accu(Map.empty, this) + } + // ----- hashing ------------------------------------------------------ /** customized hash code of this type. @@ -2086,6 +2111,8 @@ object Types { protected def apply(x: T, annot: Annotation): T = x // don't go into annotations + protected var variance = 1 + def foldOver(x: T, tp: Type): T = tp match { case tp: NamedType => this(x, tp.prefix) @@ -2097,21 +2124,36 @@ object Types { this(this(x, tp.parent), tp.refinedInfo) case tp @ MethodType(pnames, ptypes) => - this((x /: ptypes)(this), tp.resultType) + variance = -variance + val y = (x /: ptypes)(this) + variance = -variance + this(y, tp.resultType) case ExprType(restpe) => this(x, restpe) case tp @ PolyType(pnames) => - this((x /: tp.paramBounds)(this), tp.resultType) + variance = -variance + val y = (x /: tp.paramBounds)(this) + variance = -variance + this(y, tp.resultType) case SuperType(thistp, supertp) => this(this(x, thistp), supertp) case TypeBounds(lo, hi) => - if (lo eq hi) this(x, lo) - else this(this(x, lo), hi) - + if (lo eq hi) { + val saved = variance + variance = 0 + try this(x, lo) + finally variance = saved + } + else { + variance = -variance + val y = this(x, lo) + variance = -variance + this(y, hi) + } case AnnotatedType(annot, underlying) => this(this(x, annot), underlying) -- cgit v1.2.3