aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/Types.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-11-14 17:34:48 +0100
committerMartin Odersky <odersky@gmail.com>2013-11-14 17:34:48 +0100
commit9c85d93caca274943b2caf028e850261ade257d6 (patch)
tree9115ac429b34ea4abd8ca20a5fa01b706f1da796 /src/dotty/tools/dotc/core/Types.scala
parent7e46c4474d67da1472d1f0d210f123387fd1bb0f (diff)
downloaddotty-9c85d93caca274943b2caf028e850261ade257d6.tar.gz
dotty-9c85d93caca274943b2caf028e850261ade257d6.tar.bz2
dotty-9c85d93caca274943b2caf028e850261ade257d6.zip
Changes to dealiasing and widening
1) Mappers and Accumulators now reduce typerefs over refinements but do not follow general type args Following type args in asSeenFrom leads into trouble because it specializes covariant aliases too early. A later as seen from might specialize the same alias with a more specific type. 2) The isDependent test in method type now uses a custom accumulator, because it needs to not flag erroenously types of the form p.T where p is a method paramater and T is a type parameter if `p`'s type which is aliased to an argument type. It should consider the argument type instead. With the change to 1), this broke, and is fixed by 2). 3) Unstable prefixes in member are widened.
Diffstat (limited to 'src/dotty/tools/dotc/core/Types.scala')
-rw-r--r--src/dotty/tools/dotc/core/Types.scala108
1 files changed, 72 insertions, 36 deletions
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 83b8cb5dc..27e177de6 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -414,7 +414,7 @@ object Types {
/** The member of this type with the given name */
final def member(name: Name)(implicit ctx: Context): Denotation = track("member-" + name) {
- try findMember(name, this, EmptyFlags)
+ try findMember(name, widenIfUnstable, EmptyFlags)
catch {
case ex: Throwable => println(s"error occurred during: $this member $name"); throw ex // DEBUG
}
@@ -639,6 +639,13 @@ object Types {
case _ => this
}
+ /** Widen type if it is unstable (i.e. an EpxprType, or Termref to unstable symbol */
+ final def widenIfUnstable(implicit ctx: Context): Type = this match {
+ case tp: ExprType => tp.resultType.widenIfUnstable
+ case tp: TermRef if !tp.symbol.isStable => tp.underlying.widenIfUnstable
+ case _ => this
+ }
+
/** If this is an alias type, its alias, otherwise the type itself */
final def dealias(implicit ctx: Context): Type = stripTypeVar match {
case tp: TypeRef if tp.symbol.isAliasType => tp.info.bounds.hi
@@ -657,6 +664,40 @@ object Types {
case tp => tp
}
+ /** Reduce types of the form
+ *
+ * P { type T = / += / -= U } # T
+ *
+ * to just U
+ */
+ def reduceTypeRef(implicit ctx: Context): Type = this match {
+ case TypeRef(prefix, name) => lookupRefined(prefix, name) orElse this
+ case _ => this
+ }
+
+ /** The type <this . name> , reduced if possible */
+ def typeSelect(name: TypeName)(implicit ctx: Context): Type =
+ lookupRefined(this, name) orElse TypeRef(this, name)
+
+ /** The type <this . name> with given symbol, reduced if possible */
+ def typeSelect(name: TypeName, sym: TypeSymbol)(implicit ctx: Context): Type =
+ lookupRefined(this, name) orElse TypeRef.withSym(this, name, sym)
+
+ /** The type <this . sym> , reduced if possible */
+ def typeSelect(sym: TypeSymbol)(implicit ctx: Context): Type =
+ typeSelect(sym.name, sym)
+
+ private def lookupRefined(pre: Type, name: TypeName)(implicit ctx: Context): Type = pre.stripTypeVar match {
+ case pre: RefinedType =>
+ if (pre.refinedName ne name) lookupRefined(pre.parent, name)
+ else pre.refinedInfo match {
+ case TypeBounds(lo, hi) if lo eq hi => hi
+ case _ => NoType
+ }
+ case _ =>
+ NoType
+ }
+
/** Widen from constant type to its underlying non-constant
* base type.
*/
@@ -893,8 +934,8 @@ object Types {
*/
final def toBounds(tparam: Symbol)(implicit ctx: Context): TypeBounds = {
val v = tparam.variance
- if (v > 0 && !(tparam is Local)) TypeBounds.upper(this)
- else if (v < 0 && !(tparam is Local)) TypeBounds.lower(this)
+ if (v > 0 && !(tparam is LocalOrExpanded)) TypeBounds.upper(this)
+ else if (v < 0 && !(tparam is LocalOrExpanded)) TypeBounds.lower(this)
else TypeAlias(this, v)
}
@@ -1307,6 +1348,10 @@ object Types {
val prefix: Type
val name: Name
+ assert(prefix.isValueType ||
+ (prefix eq NoPrefix) ||
+ prefix.isInstanceOf[WildcardType], s"bad prefix in $prefix.$name")
+
private[this] var lastDenotationOrSym: AnyRef = null
def knownDenotation: Boolean = lastDenotationOrSym.isInstanceOf[Denotation]
@@ -1446,31 +1491,7 @@ 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 tp: SingletonType =>
- isRefinedIn(tp.widen, name)
- case _ =>
- false
- }
- if (knownDenotation &&
- ((symbol is TypeArgument | TypeParam) || 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 {
+ override def equals(that: Any) = that match {
case that: TypeRef =>
this.prefix == that.prefix &&
this.name == that.name
@@ -1638,7 +1659,7 @@ object Types {
false
}
override def computeHash = doHash(refinedName, refinedInfo, parent)
- override def toString = s"RefinedType($parent, $refinedName, $refinedInfo | hash = $hashCode)"
+ override def toString = s"RefinedType($parent, $refinedName, $refinedInfo)"
}
class CachedRefinedType(parent: Type, refinedName: Name, infoFn: RefinedType => Type) extends RefinedType(parent, refinedName)(infoFn)
@@ -1720,10 +1741,7 @@ object Types {
def isDependent(implicit ctx: Context) = {
if (!isDepKnown) {
- myIsDependent = resultType existsPart {
- case MethodParam(mt, _) => mt eq this
- case _ => false
- }
+ myIsDependent = new IsDependentAccumulator(this).apply(false, resultType)
isDepKnown = true
}
myIsDependent
@@ -2315,7 +2333,7 @@ object Types {
/** Map this function over given type */
def mapOver(tp: Type): Type = tp match {
case tp: TypeRef =>
- val tp1 = tp.losslessDealias
+ val tp1 = tp.reduceTypeRef
if (tp1 ne tp) this(tp1) else tp.derivedNamedType(this(tp.prefix))
case tp: TermRef =>
@@ -2423,8 +2441,8 @@ object Types {
def foldOver(x: T, tp: Type): T = tp match {
case tp: TypeRef =>
- val tp1 = tp.losslessDealias
- if (tp1 ne tp) this(x, tp1) else this(x, tp.prefix)
+ val tp1 = tp.reduceTypeRef
+ this(x, if (tp1 ne tp) tp1 else tp.prefix)
case tp: TermRef =>
this(x, tp.prefix)
@@ -2490,6 +2508,24 @@ object Types {
def apply(x: Boolean, tp: Type) = x || p(tp) || foldOver(x, tp)
}
+ /** An accumulator that determines whether a type contains references to
+ * `mt` via nested method parameters
+ */
+ class IsDependentAccumulator(mt: MethodType)(implicit ctx: Context) extends TypeAccumulator[Boolean] {
+ def apply(x: Boolean, tp: Type) = x || {
+ tp match {
+ case PolyParam(`mt`, _) => true
+ case tp @ TypeRef(PolyParam(`mt`, _), name) =>
+ tp.info match { // follow type arguments to avoid dependency
+ case TypeBounds(lo, hi) if lo eq hi => apply(x, hi)
+ case _ => true
+ }
+ case _ =>
+ foldOver(x, tp)
+ }
+ }
+ }
+
class NamedPartsAccumulator(p: NamedType => Boolean)(implicit ctx: Context) extends TypeAccumulator[Set[NamedType]] {
def apply(x: Set[NamedType], tp: Type): Set[NamedType] = tp match { // !!! make set linked!!!
case tp: NamedType if (p(tp)) =>