diff options
author | Martin Odersky <odersky@gmail.com> | 2013-11-03 12:45:49 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-11-03 12:50:01 +0100 |
commit | 6728b51613c6a3ee858ace014fb9c9097d15c35b (patch) | |
tree | 34799964daf5fa15e3917483991a4220e6ad50d3 /src/dotty/tools/dotc/core/Types.scala | |
parent | f920a3186427e9df2fbac97197f2f11331ef4ef3 (diff) | |
download | dotty-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.scala | 55 |
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 } |