aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/core/Scopes.scala
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2016-11-02 11:08:28 +0100
committerGuillaume Martres <smarter@ubuntu.com>2016-11-22 01:35:07 +0100
commit8a61ff432543a29234193cd1f7c14abd3f3d31a0 (patch)
treea8147561d307af862c295cfc8100d271063bb0dd /compiler/src/dotty/tools/dotc/core/Scopes.scala
parent6a455fe6da5ff9c741d91279a2dc6fe2fb1b472f (diff)
downloaddotty-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.scala437
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
+}