aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/TypeOps.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-03-09 13:35:33 +0100
committerMartin Odersky <odersky@gmail.com>2014-03-09 13:39:22 +0100
commitaf337f0667fa559411f9a96355b9ceeabf95b232 (patch)
tree25d3e9e7c55b9adcce5e744108f0ff219bb7b874 /src/dotty/tools/dotc/core/TypeOps.scala
parentd827b0180b05e7461856f668c3c4ca0ea6ed5d62 (diff)
downloaddotty-af337f0667fa559411f9a96355b9ceeabf95b232.tar.gz
dotty-af337f0667fa559411f9a96355b9ceeabf95b232.tar.bz2
dotty-af337f0667fa559411f9a96355b9ceeabf95b232.zip
Fix of #50 - volatile
Volatile checking needs to take all intersections into account; previously these could be discarded through needsChecking. Plus several refactorings and additions. 1) Module vals now have Final and Stable flags set 2) All logic around isVolatile is now in TypeOps; some of it was moved from Types. 3) Added stability checking to Select and SelectFromType typings. Todo: We should find a better name for isVolatile. Maybe define the negation instead under the name "isRealizable"?.
Diffstat (limited to 'src/dotty/tools/dotc/core/TypeOps.scala')
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala72
1 files changed, 55 insertions, 17 deletions
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index ca69ab615..15e3021a2 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -3,6 +3,8 @@ package core
import Contexts._, Types._, Symbols._, Names._, Flags._, Scopes._
import SymDenotations._
+import config.Printers._
+import Decorators._
import util.SimpleMap
trait TypeOps { this: Context =>
@@ -75,7 +77,12 @@ trait TypeOps { this: Context =>
}
final def isVolatile(tp: Type): Boolean = {
- /** Pre-filter to avoid expensive DNF computation */
+
+ /** Pre-filter to avoid expensive DNF computation
+ * If needsChecking returns false it is guaranteed that
+ * DNF does not contain intersections, or abstract types with upper
+ * bounds that themselves need checking.
+ */
def needsChecking(tp: Type, isPart: Boolean): Boolean = tp match {
case tp: TypeRef =>
tp.info match {
@@ -88,31 +95,62 @@ trait TypeOps { this: Context =>
needsChecking(tp.parent, true)
case tp: TypeProxy =>
needsChecking(tp.underlying, isPart)
- case AndType(l, r) =>
- needsChecking(l, true) || needsChecking(r, true)
- case OrType(l, r) =>
- isPart || needsChecking(l, isPart) && needsChecking(r, isPart)
+ case tp: AndType =>
+ true
+ case tp: OrType =>
+ isPart || needsChecking(tp.tp1, isPart) && needsChecking(tp.tp2, isPart)
case _ =>
false
}
+
needsChecking(tp, false) && {
- tp.DNF forall { case (parents, refinedNames) =>
+ DNF(tp) forall { case (parents, refinedNames) =>
val absParents = parents filter (_.symbol is Deferred)
- absParents.size >= 2 || {
- val ap = absParents.head
- ((parents exists (p =>
- (p ne ap)
- || p.memberNames(abstractTypeNameFilter, tp).nonEmpty
- || p.memberNames(abstractTermNameFilter, tp).nonEmpty))
- || (refinedNames & tp.memberNames(abstractTypeNameFilter, tp)).nonEmpty
- || (refinedNames & tp.memberNames(abstractTermNameFilter, tp)).nonEmpty
- || isVolatile(ap)
- )
+ absParents.nonEmpty && {
+ absParents.lengthCompare(2) >= 0 || {
+ val ap = absParents.head
+ ((parents exists (p =>
+ (p ne ap)
+ || p.memberNames(abstractTypeNameFilter, tp).nonEmpty
+ || p.memberNames(abstractTermNameFilter, tp).nonEmpty))
+ || (refinedNames & tp.memberNames(abstractTypeNameFilter, tp)).nonEmpty
+ || (refinedNames & tp.memberNames(abstractTermNameFilter, tp)).nonEmpty
+ || isVolatile(ap))
+ }
}
}
}
}
+ /** The disjunctive normal form of this type.
+ * This collects a set of alternatives, each alternative consisting
+ * of a set of typerefs and a set of refinement names. Both sets are represented
+ * as lists, to obtain a deterministic order. Collected are
+ * all type refs reachable by following aliases and type proxies, and
+ * collecting the elements of conjunctions (&) and disjunctions (|).
+ * The set of refinement names in each alternative
+ * are the set of names in refinement types encountered during the collection.
+ */
+ final def DNF(tp: Type): List[(List[TypeRef], Set[Name])] = ctx.traceIndented(s"DNF($this)", checks) {
+ tp.dealias match {
+ case tp: TypeRef =>
+ (tp :: Nil, Set[Name]()) :: Nil
+ case RefinedType(parent, name) =>
+ for ((ps, rs) <- DNF(parent)) yield (ps, rs + name)
+ case tp: TypeProxy =>
+ DNF(tp.underlying)
+ case AndType(l, r) =>
+ for ((lps, lrs) <- DNF(l); (rps, rrs) <- DNF(r))
+ yield (lps | rps, lrs | rrs)
+ case OrType(l, r) =>
+ DNF(l) | DNF(r)
+ case tp =>
+ TypeOps.emptyDNF
+ }
+ }
+
+
+
private def enterArgBinding(formal: Symbol, info: Type, cls: ClassSymbol, decls: Scope) = {
val lazyInfo = new LazyType { // needed so we do not force `formal`.
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
@@ -215,6 +253,6 @@ trait TypeOps { this: Context =>
}
object TypeOps {
-
+ val emptyDNF = (Nil, Set[Name]()) :: Nil
var track = false // !!!DEBUG
}