diff options
author | Felix Mulder <felix.mulder@gmail.com> | 2016-11-02 11:08:28 +0100 |
---|---|---|
committer | Guillaume Martres <smarter@ubuntu.com> | 2016-11-22 01:35:07 +0100 |
commit | 8a61ff432543a29234193cd1f7c14abd3f3d31a0 (patch) | |
tree | a8147561d307af862c295cfc8100d271063bb0dd /compiler/src/dotty/tools/dotc/core/Scopes.scala | |
parent | 6a455fe6da5ff9c741d91279a2dc6fe2fb1b472f (diff) | |
download | dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.tar.gz dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.tar.bz2 dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.zip |
Move compiler and compiler tests to compiler dir
Diffstat (limited to 'compiler/src/dotty/tools/dotc/core/Scopes.scala')
-rw-r--r-- | compiler/src/dotty/tools/dotc/core/Scopes.scala | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala new file mode 100644 index 000000000..3daa8117e --- /dev/null +++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala @@ -0,0 +1,437 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2012 LAMP/EPFL + * @author Martin Odersky + */ + +package dotty.tools.dotc +package core + +import Symbols._ +import Types.{TermRef, NoPrefix} +import Flags.Implicit +import Names._ +import Periods._ +import Decorators._ +import Contexts._ +import Denotations._ +import SymDenotations._ +import printing.Texts._ +import printing.Printer +import util.common._ +import util.DotClass +import SymDenotations.NoDenotation +import collection.mutable + +object Scopes { + + /** Maximal fill factor of hash table */ + private final val FillFactor = 2.0/3.0 + + /** A hashtable is created once current size exceeds MinHash * FillFactor + * The initial hash table has twice that size (i.e 16). + * This value must be a power of two, so that the index of an element can + * be computed as element.hashCode & (hashTable.length - 1) + */ + private final val MinHash = 8 + + /** The maximal permissible number of recursions when creating + * a hashtable + */ + private final val MaxRecursions = 1000 + + class ScopeEntry private[Scopes] (val name: Name, _sym: Symbol, val owner: Scope) { + + var sym: Symbol = _sym + + /** the next entry in the hash bucket + */ + var tail: ScopeEntry = null + + /** the preceding entry in this scope + */ + var prev: ScopeEntry = null + + override def toString: String = sym.toString + } + + /** A scope contains a set of symbols. It can be an extension + * of some outer scope, from which it inherits all symbols. + * This class does not have any methods to add symbols to a scope + * or to delete them. These methods are provided by subclass + * MutableScope. + */ + abstract class Scope extends DotClass with printing.Showable with Iterable[Symbol] { + + /** The last scope-entry from which all others are reachable via `prev` */ + private[dotc] def lastEntry: ScopeEntry + + /** The number of symbols in this scope (including inherited ones + * from outer scopes). + */ + def size: Int + + /** The number of outer scopes from which symbols are inherited */ + def nestingLevel: Int + + /** The symbols in this scope in the order they were entered; + * inherited from outer ones first. + */ + def toList: List[Symbol] + + /** Return all symbols as an iterator in the order they were entered in this scope. + */ + def iterator: Iterator[Symbol] = toList.iterator + + /** Returns a new mutable scope with the same content as this one. */ + def cloneScope(implicit ctx: Context): MutableScope + + /** Is the scope empty? */ + override def isEmpty: Boolean = lastEntry eq null + + /** Lookup a symbol entry matching given name. */ + def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry + + /** Lookup next entry with same name as this one */ + def lookupNextEntry(entry: ScopeEntry)(implicit ctx: Context): ScopeEntry + + /** Lookup a symbol */ + final def lookup(name: Name)(implicit ctx: Context): Symbol = { + val e = lookupEntry(name) + if (e eq null) NoSymbol else e.sym + } + + /** Returns an iterator yielding every symbol with given name in this scope. + */ + final def lookupAll(name: Name)(implicit ctx: Context): Iterator[Symbol] = new Iterator[Symbol] { + var e = lookupEntry(name) + def hasNext: Boolean = e ne null + def next(): Symbol = { val r = e.sym; e = lookupNextEntry(e); r } + } + + /** The denotation set of all the symbols with given name in this scope + * Symbols occur in the result in reverse order relative to their occurrence + * in `this.toList`. + */ + final def denotsNamed(name: Name, select: SymDenotation => Boolean = selectAll)(implicit ctx: Context): PreDenotation = { + var syms: PreDenotation = NoDenotation + var e = lookupEntry(name) + while (e != null) { + val d = e.sym.denot + if (select(d)) syms = syms union d + e = lookupNextEntry(e) + } + syms + } + + /** The scope that keeps only those symbols from this scope that match the + * given predicates. If all symbols match, returns the scope itself, otherwise + * a copy with the matching symbols. + */ + final def filteredScope(p: Symbol => Boolean)(implicit ctx: Context): Scope = { + var result: MutableScope = null + for (sym <- iterator) + if (!p(sym)) { + if (result == null) result = cloneScope + result.unlink(sym) + } + if (result == null) this else result + } + + def implicitDecls(implicit ctx: Context): List[TermRef] = Nil + + def openForMutations: MutableScope = unsupported("openForMutations") + + final def toText(printer: Printer): Text = printer.toText(this) + + def checkConsistent()(implicit ctx: Context) = () + } + + /** A subclass of Scope that defines methods for entering and + * unlinking entries. + * Note: constructor is protected to force everyone to use the factory methods newScope or newNestedScope instead. + * This is necessary because when run from reflection every scope needs to have a + * SynchronizedScope as mixin. + */ + class MutableScope protected[Scopes](initElems: ScopeEntry, initSize: Int, val nestingLevel: Int = 0) + extends Scope { + + protected[Scopes] def this(base: Scope)(implicit ctx: Context) = { + this(base.lastEntry, base.size, base.nestingLevel + 1) + ensureCapacity(MinHash)(ctx) // WTH? it seems the implicit is not in scope for a secondary constructor call. + } + + def this() = this(null, 0, 0) + + private[dotc] var lastEntry: ScopeEntry = initElems + + /** The size of the scope */ + private[this] var _size = initSize + + override final def size = _size + private def size_= (x: Int) = _size = x + + /** the hash table + */ + private var hashTable: Array[ScopeEntry] = null + + /** a cache for all elements, to be used by symbol iterator. + */ + private var elemsCache: List[Symbol] = null + + /** Clone scope, taking care not to force the denotations of any symbols in the scope. + */ + def cloneScope(implicit ctx: Context): MutableScope = { + val entries = new mutable.ArrayBuffer[ScopeEntry] + var e = lastEntry + while ((e ne null) && e.owner == this) { + entries += e + e = e.prev + } + val scope = newScope + for (i <- entries.length - 1 to 0 by -1) { + val e = entries(i) + scope.newScopeEntry(e.name, e.sym) + } + scope + } + + /** create and enter a scope entry with given name and symbol */ + protected def newScopeEntry(name: Name, sym: Symbol)(implicit ctx: Context): ScopeEntry = { + ensureCapacity(if (hashTable ne null) hashTable.length else MinHash) + val e = new ScopeEntry(name, sym, this) + e.prev = lastEntry + lastEntry = e + if (hashTable ne null) enterInHash(e) + size += 1 + elemsCache = null + e + } + + /** create and enter a scope entry */ + protected def newScopeEntry(sym: Symbol)(implicit ctx: Context): ScopeEntry = + newScopeEntry(sym.name, sym) + + private def enterInHash(e: ScopeEntry)(implicit ctx: Context): Unit = { + val idx = e.name.hashCode & (hashTable.length - 1) + e.tail = hashTable(idx) + assert(e.tail != e) + hashTable(idx) = e + } + + /** enter a symbol in this scope. */ + final def enter[T <: Symbol](sym: T)(implicit ctx: Context): T = { + if (sym.isType && ctx.phaseId <= ctx.typerPhase.id) { + assert(lookup(sym.name) == NoSymbol, + s"duplicate ${sym.debugString}; previous was ${lookup(sym.name).debugString}") // !!! DEBUG + } + newScopeEntry(sym) + sym + } + + /** enter a symbol, asserting that no symbol with same name exists in scope */ + final def enterUnique(sym: Symbol)(implicit ctx: Context): Unit = { + assert(lookup(sym.name) == NoSymbol, (sym.showLocated, lookup(sym.name).showLocated)) + enter(sym) + } + + private def ensureCapacity(tableSize: Int)(implicit ctx: Context): Unit = + if (size >= tableSize * FillFactor) createHash(tableSize * 2) + + private def createHash(tableSize: Int)(implicit ctx: Context): Unit = + if (size > tableSize * FillFactor) createHash(tableSize * 2) + else { + hashTable = new Array[ScopeEntry](tableSize) + enterAllInHash(lastEntry) + // checkConsistent() // DEBUG + } + + private def enterAllInHash(e: ScopeEntry, n: Int = 0)(implicit ctx: Context): Unit = { + if (e ne null) { + if (n < MaxRecursions) { + enterAllInHash(e.prev, n + 1) + enterInHash(e) + } else { + var entries: List[ScopeEntry] = List() + var ee = e + while (ee ne null) { + entries = ee :: entries + ee = ee.prev + } + entries foreach enterInHash + } + } + } + + /** Remove entry from this scope (which is required to be present) */ + final def unlink(e: ScopeEntry)(implicit ctx: Context): Unit = { + if (lastEntry == e) { + lastEntry = e.prev + } else { + var e1 = lastEntry + while (e1.prev != e) e1 = e1.prev + e1.prev = e.prev + } + if (hashTable ne null) { + val index = e.name.hashCode & (hashTable.length - 1) + var e1 = hashTable(index) + if (e1 == e) + hashTable(index) = e.tail + else { + while (e1.tail != e) e1 = e1.tail + e1.tail = e.tail + } + } + elemsCache = null + size -= 1 + } + + /** remove symbol from this scope if it is present */ + final def unlink(sym: Symbol)(implicit ctx: Context): Unit = { + var e = lookupEntry(sym.name) + while (e ne null) { + if (e.sym == sym) unlink(e) + e = lookupNextEntry(e) + } + } + + /** Replace symbol `prev` (if it exists in current scope) by symbol `replacement`. + * @pre `prev` and `replacement` have the same name. + */ + final def replace(prev: Symbol, replacement: Symbol)(implicit ctx: Context): Unit = { + require(prev.name == replacement.name) + var e = lookupEntry(prev.name) + while (e ne null) { + if (e.sym == prev) e.sym = replacement + e = lookupNextEntry(e) + } + elemsCache = null + } + + /** Lookup a symbol entry matching given name. + */ + override final def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { + var e: ScopeEntry = null + if (hashTable ne null) { + e = hashTable(name.hashCode & (hashTable.length - 1)) + while ((e ne null) && e.name != name) { + e = e.tail + } + } else { + e = lastEntry + while ((e ne null) && e.name != name) { + e = e.prev + } + } + e + } + + /** lookup next entry with same name as this one */ + override final def lookupNextEntry(entry: ScopeEntry)(implicit ctx: Context): ScopeEntry = { + var e = entry + if (hashTable ne null) + do { e = e.tail } while ((e ne null) && e.name != entry.name) + else + do { e = e.prev } while ((e ne null) && e.name != entry.name) + e + } + + /** Returns all symbols as a list in the order they were entered in this scope. + * Does _not_ include the elements of inherited scopes. + */ + override final def toList: List[Symbol] = { + if (elemsCache eq null) { + elemsCache = Nil + var e = lastEntry + while ((e ne null) && e.owner == this) { + elemsCache = e.sym :: elemsCache + e = e.prev + } + } + elemsCache + } + + override def implicitDecls(implicit ctx: Context): List[TermRef] = { + var irefs = new mutable.ListBuffer[TermRef] + var e = lastEntry + while (e ne null) { + if (e.sym is Implicit) { + val d = e.sym.denot + irefs += TermRef.withSigAndDenot(NoPrefix, d.name.asTermName, d.signature, d) + } + e = e.prev + } + irefs.toList + } + + /** Vanilla scope - symbols are stored in declaration order. + */ + final def sorted: List[Symbol] = toList + + override def foreach[U](p: Symbol => U): Unit = toList foreach p + + override def filter(p: Symbol => Boolean): List[Symbol] = { + var syms: List[Symbol] = Nil + var e = lastEntry + while ((e ne null) && e.owner == this) { + val sym = e.sym + if (p(sym)) syms = sym :: syms + e = e.prev + } + syms + } + + override def openForMutations: MutableScope = this + + /** Check that all symbols in this scope are in their correct hashtable buckets. */ + override def checkConsistent()(implicit ctx: Context) = { + var e = lastEntry + while (e != null) { + var e1 = lookupEntry(e.name) + while (e1 != e && e1 != null) e1 = lookupNextEntry(e1) + assert(e1 == e, s"PANIC: Entry ${e.name} is badly linked") + e = e.prev + } + } + } + + /** Create a new scope */ + def newScope: MutableScope = new MutableScope() + + /** Create a new scope nested in another one with which it shares its elements */ + def newNestedScope(outer: Scope)(implicit ctx: Context): MutableScope = new MutableScope(outer) + + /** Create a new scope with given initial elements */ + def newScopeWith(elems: Symbol*)(implicit ctx: Context): MutableScope = { + val scope = newScope + elems foreach scope.enter + scope + } + + /** Create new scope for the members of package `pkg` */ + def newPackageScope(pkgClass: Symbol): MutableScope = newScope + + /** Transform scope of members of `owner` using operation `op` + * This is overridden by the reflective compiler to avoid creating new scopes for packages + */ + def scopeTransform(owner: Symbol)(op: => MutableScope): MutableScope = op + + val selectAll: SymDenotation => Boolean = alwaysTrue + val selectPrivate: SymDenotation => Boolean = d => (d.flagsUNSAFE is Flags.Private) + val selectNonPrivate: SymDenotation => Boolean = d => !(d.flagsUNSAFE is Flags.Private) + + /** The empty scope (immutable). + */ + object EmptyScope extends Scope { + override private[dotc] def lastEntry = null + override def size = 0 + override def nestingLevel = 0 + override def toList = Nil + override def cloneScope(implicit ctx: Context): MutableScope = unsupported("cloneScope") + override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = null + override def lookupNextEntry(entry: ScopeEntry)(implicit ctx: Context): ScopeEntry = null + } + + /** A class for error scopes (mutable) + */ + class ErrorScope(owner: Symbol) extends MutableScope +} |