aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/Types.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-08-07 20:25:23 +0200
committerMartin Odersky <odersky@gmail.com>2014-08-08 18:32:09 +0200
commitf87153bc5d74f66e2fcf22dc7282da31813430da (patch)
tree02ec1ea59e55e895140e5f1b1e3ec9a09c18ce92 /src/dotty/tools/dotc/core/Types.scala
parent9748c9bd54e278e65a29dff6c78fba5b1534ac00 (diff)
downloaddotty-f87153bc5d74f66e2fcf22dc7282da31813430da.tar.gz
dotty-f87153bc5d74f66e2fcf22dc7282da31813430da.tar.bz2
dotty-f87153bc5d74f66e2fcf22dc7282da31813430da.zip
Detect cycles and protected legal ones with LazyRefs
Cycles are now detected early, when an info is first completed. Legal, f-bounded cycles are broken by a LazyRef, which will construct its type lazily. This makes checkBounds validation of AppliedTypeTrees work (in FirstTransform). Formerly, this stackoverflowed despite the laziness precautions in findMember. Todo: Do the same for class files coming from Java and Scala 2.x.
Diffstat (limited to 'src/dotty/tools/dotc/core/Types.scala')
-rw-r--r--src/dotty/tools/dotc/core/Types.scala31
1 files changed, 29 insertions, 2 deletions
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 592b7b55f..a81d200d3 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -31,6 +31,8 @@ import language.implicitConversions
object Types {
+ private var recCount = 0
+
/** The class of types.
* The principal subclasses and sub-objects are as follows:
*
@@ -379,6 +381,8 @@ object Types {
* flags in `excluded` from consideration.
*/
final def findMember(name: Name, pre: Type, excluded: FlagSet)(implicit ctx: Context): Denotation = try {
+ recCount += 1
+ assert(recCount < 20)
@tailrec def go(tp: Type): Denotation = tp match {
case tp: RefinedType =>
if (name eq tp.refinedName) goRefined(tp) else go(tp.parent)
@@ -436,8 +440,10 @@ object Types {
case ex: MergeError =>
throw new MergeError(s"${ex.getMessage} as members of type ${pre.show}")
case ex: Throwable =>
- println(s"error occurred during: $this: ${this.widen} member $name")
+ println(i"findMember exception for $this: ${this.widen} member $name")
throw ex // DEBUG
+ } finally {
+ recCount -= 1
}
/** The set of names of members of this type that pass the given name filter
@@ -599,7 +605,9 @@ object Types {
case _ => this
}
- /** Follow aliases until type is no longer an alias type. */
+ /** Follow aliases and derefernces LazyRefs and instantiated TypeVars until type
+ * is no longer alias type, LazyRef, or instantiated type variable.
+ */
final def dealias(implicit ctx: Context): Type = this match {
case tp: TypeRef =>
tp.info match {
@@ -609,6 +617,8 @@ object Types {
case tp: TypeVar =>
val tp1 = tp.instanceOpt
if (tp1.exists) tp1.dealias else tp
+ case tp: LazyRef =>
+ tp.ref.dealias
case tp => tp
}
@@ -643,6 +653,14 @@ object Types {
case _ => NoType
}
+ /** The chain of underlying types as long as type is a TypeProxy.
+ * Useful for diagnostics
+ */
+ def underlyingChain(implicit ctx: Context): List[Type] = this match {
+ case tp: TypeProxy => tp :: tp.underlying.underlyingChain
+ case _ => Nil
+ }
+
/** A prefix-less termRef to a new skolem symbol that has the given type as info */
def narrow(implicit ctx: Context): TermRef = TermRef(NoPrefix, ctx.newSkolem(this))
@@ -1469,6 +1487,12 @@ object Types {
unique(new CachedConstantType(value))
}
+ case class LazyRef(refFn: () => Type) extends UncachedProxyType with TermType {
+ lazy val ref = refFn()
+ override def underlying(implicit ctx: Context) = ref
+ override def toString = s"LazyRef($ref)"
+ }
+
// --- Refined Type ---------------------------------------------------------
/** A refined type parent { refinement }
@@ -2408,6 +2432,9 @@ object Types {
case tp @ SuperType(thistp, supertp) =>
tp.derivedSuperType(this(thistp), this(supertp))
+ case tp: LazyRef =>
+ LazyRef(() => this(tp.ref))
+
case tp: ClassInfo =>
mapClassInfo(tp)