aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/TypeOps.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-01-10 12:23:23 +0100
committerMartin Odersky <odersky@gmail.com>2013-01-10 12:23:23 +0100
commitf703cd3b404a8a996b8ad100b4a43acb5cdd73a8 (patch)
tree81c35a9d3b90e8c1fa4e57f4f9d8638f47f4a98d /src/dotty/tools/dotc/core/TypeOps.scala
parent15927bbb22e4c7d3f4ce45deca282081297a8c41 (diff)
downloaddotty-f703cd3b404a8a996b8ad100b4a43acb5cdd73a8.tar.gz
dotty-f703cd3b404a8a996b8ad100b4a43acb5cdd73a8.tar.bz2
dotty-f703cd3b404a8a996b8ad100b4a43acb5cdd73a8.zip
Refactored Types to move auxiliary operations into Context. Moved per-run state into RootContext.
Diffstat (limited to 'src/dotty/tools/dotc/core/TypeOps.scala')
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala210
1 files changed, 210 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
new file mode 100644
index 000000000..a0cc00b4b
--- /dev/null
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -0,0 +1,210 @@
+package dotty.tools.dotc.core
+
+import Contexts._, Types._, Symbols._
+
+trait TypeOps { this: Context =>
+
+ final def asSeenFrom(tp: Type, pre: Type, clazz: Symbol, theMap: AsSeenFromMap): Type = {
+
+ def skipPrefixOf(pre: Type, clazz: Symbol) =
+ (pre eq NoType) || (pre eq NoPrefix) || clazz.isPackageClass
+
+ def toPrefix(pre: Type, clazz: Symbol, thisclazz: ClassSymbol): Type =
+ if (skipPrefixOf(pre, clazz))
+ tp
+ else if ((thisclazz isNonBottomSubClass clazz) &&
+ (pre.widen.typeSymbol isNonBottomSubClass thisclazz))
+ pre match {
+ case SuperType(thistp, _) => thistp
+ case _ => pre
+ }
+ else
+ toPrefix(pre.baseType(clazz).normalizedPrefix, clazz.owner, thisclazz)
+
+ def toInstance(pre: Type, clazz: Symbol, tparam: Symbol): Type = {
+ if (skipPrefixOf(pre, clazz)) tp
+ else {
+ val tparamOwner = tparam.owner
+
+ def throwError =
+ if (tparamOwner.info.parents exists (_.isErroneous))
+ ErrorType // don't be overzealous with throwing exceptions, see #2641
+ else
+ throw new Error(
+ s"something is wrong (wrong class file?): ${tparam.locationString} cannot be instantiated from ${pre.widen}")
+
+ def prefixMatches = pre.typeSymbol isNonBottomSubClass tparamOwner
+
+ val basePre = pre.baseType(clazz)
+
+ def instParamFrom(typeInst: Type): Type = typeInst match {
+ case ConstantType(_) =>
+ // have to deconst because it may be a Class[T].
+ instParamFrom(typeInst.deconst)
+ case AppliedType(tycon, baseArgs) =>
+ instParam(tycon.typeParams, baseArgs)
+ case _ =>
+ throwError
+ }
+
+ def instParam(ps: List[Symbol], as: List[Type]): Type =
+ if (ps.isEmpty || as.isEmpty) throwError
+ else if (tparam eq ps.head) as.head
+ else throwError
+
+ if (tparamOwner == clazz && prefixMatches) instParamFrom(basePre)
+ else toInstance(basePre.normalizedPrefix, clazz.owner, tparam)
+ }
+ }
+
+ tp match {
+ case tp: NamedType =>
+ val sym = tp.symbol
+ if (tp.symbol.isTypeParameter) toInstance(pre, clazz, sym)
+ else if (sym.isStatic) tp
+ else tp.derivedNamedType(asSeenFrom(tp.prefix, pre, clazz, theMap), tp.name)
+ case ThisType(thisclazz) =>
+ toPrefix(pre, clazz, thisclazz)
+ case _ =>
+ val asSeenFromMap = if (theMap != null) theMap else new AsSeenFromMap(pre, clazz)
+ tp match {
+ case tp: AppliedType =>
+ tp.derivedAppliedType(
+ asSeenFromMap(tp.tycon), tp.targs mapConserve asSeenFromMap)
+ case _ =>
+ asSeenFromMap mapOver tp
+ }
+ }
+ }
+
+ class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap {
+ def apply(tp: Type) = asSeenFrom(tp, pre, clazz, this)
+ }
+
+ final def isVolatile(tp: Type): Boolean = {
+ def isAbstractIntersection(tp: Type): Boolean = tp match {
+ case tp: TypeRef => tp.isAbstractType
+ case AndType(l, r) => isAbstractIntersection(l) | isAbstractIntersection(l)
+ case OrType(l, r) => isAbstractIntersection(l) & isAbstractIntersection(r)
+ case _ => false
+ }
+ def test = {
+ tp match {
+ case ThisType(_) =>
+ false
+ case RefinedType(p, names) =>
+ p.isVolatile ||
+ isAbstractIntersection(p) &&
+ (names exists (tp.abstractMemberNames(tp) contains))
+ case tp: TypeProxy =>
+ tp.underlying.isVolatile
+ case AndType(l, r) =>
+ l.isVolatile || r.isVolatile ||
+ isAbstractIntersection(l) && r.abstractMemberNames(tp).nonEmpty
+ case OrType(l, r) =>
+ l.isVolatile && r.isVolatile
+ case _ =>
+ false
+ }
+ }
+ // need to be careful not to fall into an infinite recursion here
+ // because volatile checking is done before all cycles are detected.
+ // the case to avoid is an abstract type directly or
+ // indirectly upper-bounded by itself. See #2918
+ import ctx.root.{volatileRecursions, pendingVolatiles}
+ try {
+ volatileRecursions += 1
+ if (volatileRecursions < LogVolatileThreshold)
+ test
+ else if (pendingVolatiles(tp))
+ false // we can return false here, because a cycle will be detected
+ // here afterwards and an error will result anyway.
+ else
+ try {
+ pendingVolatiles += tp
+ test
+ } finally {
+ pendingVolatiles -= tp
+ }
+ } finally {
+ volatileRecursions -= 1
+ }
+ }
+
+ final def glb (tp1: Type, tp2: Type): Type =
+ if (tp1 eq tp2) tp1
+ else if (tp1.isWrong) tp2
+ else if (tp2.isWrong) tp1
+ else tp2 match {
+ case OrType(tp21, tp22) =>
+ tp1 & tp21 | tp1 & tp22
+ case _ =>
+ tp1 match {
+ case OrType(tp11, tp12) =>
+ tp11 & tp2 | tp12 & tp2
+ case _ =>
+ val t1 = mergeIfSub(tp1, tp2)
+ if (t1.exists) t1
+ else {
+ val t2 = mergeIfSub(tp2, tp1)
+ if (t2.exists) t2
+ else AndType(tp1, tp2)
+ }
+ }
+ }
+
+ def lub (tp1: Type, tp2: Type): Type =
+ if (tp1 eq tp2) tp1
+ else if (tp1.isWrong) tp1
+ else if (tp2.isWrong) tp2
+ else {
+ val t1 = mergeIfSuper(tp1, tp2)
+ if (t1.exists) t1
+ else {
+ val t2 = mergeIfSuper(tp2, tp1)
+ if (t2.exists) t2
+ else OrType(tp1, tp2)
+ }
+ }
+
+ /** Merge `t1` into `tp2` if t1 is a subtype of some part of tp2.
+ */
+ private def mergeIfSub(tp1: Type, tp2: Type)(implicit ctx: Context): Type =
+ if (tp1 <:< tp2)
+ if (tp2 <:< tp1) tp2 else tp1
+ else tp2 match {
+ case tp2 @ AndType(tp21, tp22) =>
+ val lower1 = mergeIfSub(tp1, tp21)
+ if (lower1 eq tp21) tp2
+ else if (lower1.exists) lower1 & tp22
+ else {
+ val lower2 = mergeIfSub(tp1, tp22)
+ if (lower2 eq tp22) tp2
+ else if (lower2.exists) tp21 & lower2
+ else NoType
+ }
+ case _ =>
+ NoType
+ }
+
+ /** Merge `tp1` into `tp2` if tp1 is a supertype of some part of tp2.
+ */
+ private def mergeIfSuper(tp1: Type, tp2: Type)(implicit ctx: Context): Type =
+ if (tp2 <:< tp1)
+ if (tp1 <:< tp2) tp2 else tp1
+ else tp2 match {
+ case tp2 @ OrType(tp21, tp22) =>
+ val higher1 = mergeIfSuper(tp1, tp21)
+ if (higher1 eq tp21) tp2
+ else if (higher1.exists) higher1 | tp22
+ else {
+ val higher2 = mergeIfSuper(tp1, tp22)
+ if (higher2 eq tp22) tp2
+ else if (higher2.exists) tp21 | higher2
+ else NoType
+ }
+ case _ =>
+ NoType
+ }
+}
+