diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/core/Flags.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/NameOps.scala | 9 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/SymDenotations.scala | 42 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/OverridingPairs.scala | 146 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/SuperAccessors.scala | 2 |
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) } |