aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/Types.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-11-03 12:45:49 +0100
committerMartin Odersky <odersky@gmail.com>2013-11-03 12:50:01 +0100
commit6728b51613c6a3ee858ace014fb9c9097d15c35b (patch)
tree34799964daf5fa15e3917483991a4220e6ad50d3 /src/dotty/tools/dotc/core/Types.scala
parentf920a3186427e9df2fbac97197f2f11331ef4ef3 (diff)
downloaddotty-6728b51613c6a3ee858ace014fb9c9097d15c35b.tar.gz
dotty-6728b51613c6a3ee858ace014fb9c9097d15c35b.tar.bz2
dotty-6728b51613c6a3ee858ace014fb9c9097d15c35b.zip
Adding simplification and fixing a variance problem.
1. Added a "simplified" method which gets called on type varianvle instantiation and interpolation. 2. Fixed a problem in TypeAccumulator which did not take the variance into account for Co/Contra type aliases.
Diffstat (limited to 'src/dotty/tools/dotc/core/Types.scala')
-rw-r--r--src/dotty/tools/dotc/core/Types.scala55
1 files changed, 52 insertions, 3 deletions
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index ba8b4f139..f27822639 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -1092,6 +1092,9 @@ object Types {
case None =>
vmap updated (t, variance)
}
+ case t: TypeRef =>
+ val t1 = t.losslessDealias
+ if (t1 ne t) apply(vmap, t1) else foldOver(vmap, t)
case _ =>
foldOver(vmap, t)
}
@@ -1099,6 +1102,30 @@ object Types {
accu(Map.empty, this)
}
+ /** A simplified version of this type which is equivalent wrt =:= to this type.
+ * Rules applied are:
+ * T { type U = V } # U --> V
+ * Also, type variables are instantiated and &/| operations are re-done because
+ * what was a union or intersection of type variables might be a simpler type
+ * after the type variables are instantiated.
+ */
+ def simplified(implicit ctx: Context) = {
+ class Simplify extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case tp: TypeRef =>
+ val tp1 = tp.losslessDealias
+ if (tp1 ne tp) apply(tp1) else mapOver(tp)
+ case AndType(l, r) =>
+ mapOver(l) & mapOver(r)
+ case OrType(l, r) =>
+ mapOver(l) | mapOver(r)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+ new Simplify().apply(this)
+ }
+
// ----- hashing ------------------------------------------------------
/** customized hash code of this type.
@@ -1409,6 +1436,28 @@ object Types {
}
abstract case class TypeRef(override val prefix: Type, name: TypeName) extends NamedType {
+
+ /** If this TypeRef can be dealiased, its alias type, otherwise the type itself.
+ * A TypeRef can be safely dealiased if it refers to an alias type and either the
+ * referenced name is a type parameter or it is refined in the prefix of the TypeRef.
+ * The idea is than in those two cases we don't lose any info or clarity by
+ * dereferencing.
+ */
+ def losslessDealias(implicit ctx: Context) = {
+ def isRefinedIn(tp: Type, name: Name): Boolean = tp match {
+ case RefinedType(parent, refinedName) =>
+ name == refinedName || isRefinedIn(parent, name)
+ case _ =>
+ false
+ }
+ if ((symbol is TypeArgument) || isRefinedIn(prefix, name))
+ info match {
+ case TypeBounds(lo, hi) if lo eq hi => hi
+ case _ => this
+ }
+ else this
+ }
+
override def equals(that: Any) = that match {
case that: TypeRef =>
this.prefix == that.prefix &&
@@ -1951,7 +2000,7 @@ object Types {
var inst = ctx.typeComparer.approximate(origin, fromBelow)
if (fromBelow && isSingleton(inst) && !isSingleton(upperBound))
inst = inst.widen
- instantiateWith(inst)
+ instantiateWith(inst.simplified)
}
}
@@ -2383,10 +2432,10 @@ object Types {
case SuperType(thistp, supertp) =>
this(this(x, thistp), supertp)
- case TypeBounds(lo, hi) =>
+ case bounds @ TypeBounds(lo, hi) =>
if (lo eq hi) {
val saved = variance
- variance = 0
+ variance = variance * bounds.variance
try this(x, lo)
finally variance = saved
}