aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-07-16 14:46:05 +0200
committerMartin Odersky <odersky@gmail.com>2014-08-03 17:28:33 +0200
commit2cb905004b28707b4c127e5a1848084109ddb3db (patch)
tree960c4fa917c6128efe2f02b8f2d90855558903e9 /src/dotty/tools/dotc
parent51eeac782a01c19a24184f0ef177845af514b47f (diff)
downloaddotty-2cb905004b28707b4c127e5a1848084109ddb3db.tar.gz
dotty-2cb905004b28707b4c127e5a1848084109ddb3db.tar.bz2
dotty-2cb905004b28707b4c127e5a1848084109ddb3db.zip
Preparation for intgeration of RefChecks
Added OverridingPairs Small tweaks here and there.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala3
-rw-r--r--src/dotty/tools/dotc/core/NameOps.scala9
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala42
-rw-r--r--src/dotty/tools/dotc/transform/OverridingPairs.scala146
-rw-r--r--src/dotty/tools/dotc/transform/SuperAccessors.scala2
5 files changed, 179 insertions, 23 deletions
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index c467a553f..c67768861 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -521,6 +521,9 @@ object Flags {
/** A Java companion object */
final val JavaModule = allOf(JavaDefined, Module)
+ /** A Java companion object */
+ final val JavaProtected = allOf(JavaDefined, Protected)
+
/** Labeled private[this] */
final val PrivateLocal = allOf(Private, Local)
diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala
index 404a0844a..d32fd1913 100644
--- a/src/dotty/tools/dotc/core/NameOps.scala
+++ b/src/dotty/tools/dotc/core/NameOps.scala
@@ -251,9 +251,12 @@ object NameOps {
/** If this is a default getter, its index (starting from 0), else -1 */
def defaultGetterIndex: Int = {
- val p = name.indexOfSlice(DEFAULT_GETTER)
- if (p >= 0) name.drop(p + DEFAULT_GETTER.length).toString.toInt - 1
- else -1
+ var i = name.length
+ while (i > 0 && name(i - 1).isDigit) i -= 1
+ if (i > 0 && i < name.length && name.take(i).endsWith(DEFAULT_GETTER))
+ name.drop(i).toString.toInt - 1
+ else
+ -1
}
/** The name of an accessor for protected symbols. */
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index b0a09baf0..00c3d7666 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -589,10 +589,13 @@ object SymDenotations {
NoSymbol
}
- /** The field accessed by this getter or setter */
- def accessedField(implicit ctx: Context): Symbol = {
+ /** The field accessed by this getter or setter, or if it does not exist, the getter */
+ def accessedFieldOrGetter(implicit ctx: Context): Symbol = {
val fieldName = if (isSetter) name.asTermName.setterToGetter else name
- owner.info.decl(fieldName).suchThat(d => !(d is Method)).symbol
+ val d = owner.info.decl(fieldName)
+ val field = d.suchThat(!_.is(Method)).symbol
+ def getter = d.suchThat(_.info.isParameterless).symbol
+ field orElse getter
}
/** The chain of owners of this denotation, starting with the denoting symbol itself */
@@ -723,17 +726,29 @@ object SymDenotations {
denot.symbol
}
+ /** If false, this symbol cannot possibly participate in an override,
+ * either as overrider or overridee.
+ */
+ final def canMatchInheritedSymbols(implicit ctx: Context): Boolean =
+ maybeOwner.isClass && !isConstructor && !is(Private)
+
/** The symbol, in class `inClass`, that is overridden by this denotation. */
final def overriddenSymbol(inClass: ClassSymbol)(implicit ctx: Context): Symbol =
- if ((this is Private) && (owner ne inClass)) NoSymbol
+ if (!canMatchInheritedSymbols && (owner ne inClass)) NoSymbol
else matchingSymbol(inClass, owner.thisType)
/** All symbols overriden by this denotation. */
final def allOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] =
- if (exists && owner.isClass)
- owner.info.baseClasses.tail.iterator map overriddenSymbol filter (_.exists)
- else
- Iterator.empty
+ if (!canMatchInheritedSymbols) Iterator.empty
+ else overriddenFromType(owner.info)
+
+ /** Returns all all matching symbols defined in parents of the selftype. */
+ final def extendedOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] =
+ if (!canMatchInheritedSymbols) Iterator.empty
+ else overriddenFromType(owner.asClass.classInfo.selfType)
+
+ private def overriddenFromType(tp: Type)(implicit ctx: Context): Iterator[Symbol] =
+ tp.baseClasses.tail.iterator map overriddenSymbol filter (_.exists)
/** The symbol overriding this symbol in given subclass `ofclazz`.
*
@@ -743,17 +758,6 @@ object SymDenotations {
if (canMatchInheritedSymbols) matchingSymbol(inClass, inClass.thisType)
else NoSymbol
- /** If false, this symbol cannot possibly participate in an override,
- * either as overrider or overridee. For internal use; you should consult
- * with isOverridingSymbol. This is used by isOverridingSymbol to escape
- * the recursive knot.
- */
- private def canMatchInheritedSymbols = (
- owner.isClass
- && !this.isClass
- && !this.isConstructor
- )
-
/** The symbol accessed by a super in the definition of this symbol when
* seen from class `base`. This symbol is always concrete.
* pre: `this.owner` is in the base class sequence of `base`.
diff --git a/src/dotty/tools/dotc/transform/OverridingPairs.scala b/src/dotty/tools/dotc/transform/OverridingPairs.scala
new file mode 100644
index 000000000..5c857bc38
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/OverridingPairs.scala
@@ -0,0 +1,146 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import Flags._, Symbols._, Contexts._, Types._, Scopes._
+import util.HashSet
+import collection.mutable.HashMap
+import collection.immutable.BitSet
+import scala.annotation.tailrec
+
+/** A class that yields a kind of iterator (`Cursor`),
+ * which yields all pairs of overriding/overridden symbols
+ * that are visible in some baseclass, unless there's a parent class
+ * that already contains the same pairs.
+ *
+ * Adapted from the 2.9 version of OverridingPairs. The 2.10 version is IMO
+ * way too unwieldy to be maintained.
+ */
+abstract class OverridingPairs {
+
+ /** The cursor class
+ * @param base the base class that contains the overriding pairs
+ */
+ class Cursor(base: Symbol)(implicit ctx: Context) {
+
+ private val self = base.thisType
+
+ /** Symbols to exclude: Here these are constructors and private locals.
+ * But it may be refined in subclasses.
+ */
+ protected def exclude(sym: Symbol): Boolean =
+ sym.isConstructor || sym.is(PrivateLocal)
+
+ /** The parents of base (may also be refined).
+ */
+ protected def parents: Array[Symbol] = base.info.parents.toArray map (_.typeSymbol)
+
+ /** Does `sym1` match `sym2` so that it qualifies as overriding.
+ * Types always match. Term symbols match if their membertypes
+ * relative to <base>.this do
+ */
+ protected def matches(sym1: Symbol, sym2: Symbol): Boolean =
+ sym1.isType || {
+ val info1 = self.memberInfo(sym1)
+ val info2 = self.memberInfo(sym2)
+ // info1.signature == info2.signature && // TODO enable for speed
+ info1 matches info2
+ }
+
+ /** The symbols that can take part in an overriding pair */
+ private val decls = {
+ val decls = newScope
+ // fill `decls` with overriding shadowing overridden */
+ def fillDecls(bcs: List[Symbol], deferred: Boolean): Unit = bcs match {
+ case bc :: bcs1 =>
+ fillDecls(bcs1, deferred)
+ var e = bc.info.decls.asInstanceOf[MutableScope].lastEntry
+ while (e != null) {
+ if (e.sym.is(Deferred) == deferred && !exclude(e.sym))
+ decls.enter(e.sym)
+ e = e.prev
+ }
+ case nil =>
+ }
+ // first, deferred (this will need to change if we change lookup rules!
+ fillDecls(base.info.baseClasses, deferred = true)
+ // then, concrete.
+ fillDecls(base.info.baseClasses, deferred = false)
+ decls
+ }
+
+ private val subParents = {
+ val subParents = new HashMap[Symbol, BitSet]
+ for (bc <- base.info.baseClasses)
+ subParents(bc) = BitSet(parents.indices.filter(parents(_).derivesFrom(bc)): _*)
+ subParents
+ }
+
+ private def hasCommonParentAsSubclass(cls1: Symbol, cls2: Symbol): Boolean =
+ (subParents(cls1) intersect subParents(cls2)).isEmpty
+
+ /** The scope entries that have already been visited as overridden
+ * (maybe excluded because of hasCommonParentAsSubclass).
+ * These will not appear as overriding
+ */
+ private val visited = new HashSet[ScopeEntry](64)
+
+ /** The current entry candidate for overriding
+ */
+ private var curEntry = decls.lastEntry
+
+ /** The current entry candidate for overridden */
+ private var nextEntry = curEntry
+
+ /** The current candidate symbol for overriding */
+ var overriding: Symbol = _
+
+ /** If not null: The symbol overridden by overriding */
+ var overridden: Symbol = _
+
+ //@M: note that next is called once during object initialization
+ def hasNext: Boolean = curEntry ne null
+
+ @tailrec
+ final def next: Unit = {
+ if (curEntry ne null) {
+ overriding = curEntry.sym
+ if (nextEntry ne null) {
+ val overridingOwner = overriding.owner
+ do {
+ do {
+ nextEntry = decls.lookupNextEntry(nextEntry);
+ /* DEBUG
+ if ((nextEntry ne null) &&
+ !(nextEntry.sym hasFlag PRIVATE) &&
+ !(overriding.owner == nextEntry.sym.owner) &&
+ !matches(overriding, nextEntry.sym))
+ println("skipping "+overriding+":"+self.memberType(overriding)+overriding.locationString+" to "+nextEntry.sym+":"+self.memberType(nextEntry.sym)+nextEntry.sym.locationString)
+ */
+ } while ((nextEntry ne null) &&
+ (//!!!!nextEntry.sym.canMatchInheritedSymbols ||
+ (overriding.owner == nextEntry.sym.owner) ||
+ (!matches(overriding, nextEntry.sym)) ||
+ (exclude(overriding))))
+ if (nextEntry ne null) visited.addEntry(nextEntry)
+ // skip nextEntry if a class in `parents` is a subclass of the owners of both
+ // overriding and nextEntry.sym
+ } while ((nextEntry ne null) &&
+ hasCommonParentAsSubclass(overridingOwner, nextEntry.sym.owner))
+ if (nextEntry ne null) {
+ overridden = nextEntry.sym;
+ //Console.println("yield: " + overriding + overriding.locationString + " / " + overridden + overridden.locationString);//DEBUG
+ } else {
+ do {
+ curEntry = curEntry.prev
+ } while ((curEntry ne null) && visited.contains(curEntry))
+ nextEntry = curEntry
+ next
+ }
+ }
+ }
+ }
+
+ next
+ }
+}
diff --git a/src/dotty/tools/dotc/transform/SuperAccessors.scala b/src/dotty/tools/dotc/transform/SuperAccessors.scala
index 52306956e..cd9de03ec 100644
--- a/src/dotty/tools/dotc/transform/SuperAccessors.scala
+++ b/src/dotty/tools/dotc/transform/SuperAccessors.scala
@@ -356,7 +356,7 @@ class SuperAccessors extends MacroTransform with IdentityDenotTransformer { this
case Super(_, mix) =>
if ((sym.isTerm) && !(sym is Method) || (sym is Accessor)) {
- ctx.error(s"super may be not be used on ${sym.accessedField orElse sym}", tree.pos)
+ ctx.error(s"super may be not be used on ${sym.accessedFieldOrGetter orElse sym}", tree.pos)
} else if (isDisallowed(sym)) {
ctx.error(s"super not allowed here: use this.${name.decode} instead", tree.pos)
}