package scala.tools.nsc
package transform
import collection.mutable.HashMap
import symtab.Flags._
import util.HashSet
import annotation.tailrec
abstract class OverridingPairs {
val global: Global
import global._
class Cursor(base: Symbol) {
private val self = base.thisType
protected def exclude(sym: Symbol): Boolean =
sym.isConstructor || sym.isPrivateLocal || sym.hasFlag(BRIDGE)
protected def parents: List[Type] = base.info.parents
protected def matches(sym1: Symbol, sym2: Symbol): Boolean =
sym1.isType || (self.memberType(sym1) matches self.memberType(sym2))
private type BitSet = Array[Int]
private def include(bs: BitSet, n: Int) {
val nshifted = n >> 5
val nmask = 1 << (n & 31)
bs(nshifted) = bs(nshifted) | nmask
}
private def intersectionContainsElementLeq(bs1: BitSet, bs2: BitSet, n: Int): Boolean = {
val nshifted = n >> 5
val nmask = 1 << (n & 31)
var i = 0
while (i < nshifted) {
if ((bs1(i) & bs2(i)) != 0) return true
i += 1
}
(bs1(nshifted) & bs2(nshifted) & (nmask | nmask - 1)) != 0
}
private val decls = new Scope
{ def fillDecls(bcs: List[Symbol], deferredflag: Int) {
if (!bcs.isEmpty) {
fillDecls(bcs.tail, deferredflag)
var e = bcs.head.info.decls.elems;
while (e ne null) {
if (e.sym.getFlag(DEFERRED) == deferredflag.toLong && !exclude(e.sym))
decls enter e.sym;
e = e.next
}
}
}
fillDecls(base.info.baseClasses, DEFERRED)
fillDecls(base.info.baseClasses, 0)
}
private val size = base.info.baseClasses.length
private val index = new HashMap[Symbol, Int]
{ var i = 0
for (bc <- base.info.baseClasses) {
index(bc) = i
i += 1
}
}
private val subParents = new Array[BitSet](size)
{ for (i <- List.range(0, size))
subParents(i) = new BitSet(size);
for (p <- parents) {
index get p.typeSymbol match {
case Some(pIndex) =>
for (bc <- p.baseClasses)
if (p.baseType(bc) =:= self.baseType(bc))
index get bc match {
case Some(bcIndex) =>
include(subParents(bcIndex), pIndex)
case None =>
}
else if (settings.debug.value)
log("SKIPPING "+p+" -> "+p.baseType(bc)+" / "+self.baseType(bc)+" from "+base)
case None =>
}
}
}
private def hasCommonParentAsSubclass(sym1: Symbol, sym2: Symbol) = (
for (index1 <- index get sym1.owner ; index2 <- index get sym2.owner) yield
intersectionContainsElementLeq(subParents(index1), subParents(index2), index1 min index2)
).exists(_ == true)
private val visited = HashSet[ScopeEntry]("visited", 64)
private var curEntry = decls.elems
private var nextEntry = curEntry
var overriding: Symbol = _
var overridden: Symbol = _
def hasNext: Boolean = curEntry ne null
@tailrec
final def next() {
if (curEntry ne null) {
overriding = curEntry.sym
if (nextEntry ne null) {
do {
do {
nextEntry = decls.lookupNextEntry(nextEntry);
} while ((nextEntry ne null) &&
((nextEntry.sym hasFlag PRIVATE) ||
(overriding.owner == nextEntry.sym.owner) ||
(!matches(overriding, nextEntry.sym)) ||
(exclude(overriding))))
if (nextEntry ne null) visited addEntry nextEntry
} while ((nextEntry ne null) && (hasCommonParentAsSubclass(overriding, nextEntry.sym)))
if (nextEntry ne null) {
overridden = nextEntry.sym;
} else {
do {
curEntry = curEntry.next
} while ((curEntry ne null) && (visited contains curEntry));
nextEntry = curEntry
next
}
}
}
}
next
}
}