aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/Scopes.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-03-03 16:10:21 +0100
committerMartin Odersky <odersky@gmail.com>2013-03-03 16:10:21 +0100
commita1049e6227d412ce6bdd9065a350cb20921987e2 (patch)
tree506849218a5178916e6fa87e0d0f0636e50e4434 /src/dotty/tools/dotc/core/Scopes.scala
parent30bfa5b1be62652fc07292d36ed1261edbcdb362 (diff)
downloaddotty-a1049e6227d412ce6bdd9065a350cb20921987e2.tar.gz
dotty-a1049e6227d412ce6bdd9065a350cb20921987e2.tar.bz2
dotty-a1049e6227d412ce6bdd9065a350cb20921987e2.zip
Split scopes into immutable and mutable parts.
The goal is that symbols should be entered/deleted directly into classes instead of their scopes. This is necesaary so that invariant about fingerPrint can be maintained. We achieve it by making the info scope have immutable type, so an explicit cast is needed to get around that.
Diffstat (limited to 'src/dotty/tools/dotc/core/Scopes.scala')
-rw-r--r--src/dotty/tools/dotc/core/Scopes.scala168
1 files changed, 99 insertions, 69 deletions
diff --git a/src/dotty/tools/dotc/core/Scopes.scala b/src/dotty/tools/dotc/core/Scopes.scala
index 51e5419e6..89bdeb94b 100644
--- a/src/dotty/tools/dotc/core/Scopes.scala
+++ b/src/dotty/tools/dotc/core/Scopes.scala
@@ -42,12 +42,81 @@ object Scopes {
override def toString: String = sym.toString
}
- /** Note: constructor is protected to force everyone to use the factory methods newScope or newNestedScope instead.
+ /** 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 Iterable[Symbol] {
+ 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 scope with the same content as this one. */
+ def cloneScope(implicit ctx: Context): Scope
+
+ /** 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 */
+ final def denotsNamed(name: Name)(implicit ctx: Context): PreDenotation = {
+ var syms: PreDenotation = NoDenotation
+ var e = lookupEntry(name)
+ while (e != null) {
+ syms = syms union e.sym.denot
+ e = lookupNextEntry(e)
+ }
+ syms
+ }
+
+ /** Cast this scope to a mutable scope */
+ final def openForMutations: MutableScope = this.asInstanceOf[MutableScope]
+ }
+
+ /** 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 Scope protected[Scopes](initElems: ScopeEntry, initSize: Int, val nestingLevel: Int = 0)
- extends Iterable[Symbol] {
+ 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)
@@ -61,7 +130,7 @@ object Scopes {
/** The size of the scope */
private[this] var _size = initSize
- override def size = _size
+ override final def size = _size
private def size_= (x: Int) = _size = x
/** the hash table
@@ -72,11 +141,7 @@ object Scopes {
*/
private var elemsCache: List[Symbol] = null
- /** Returns a new scope with the same content as this one. */
- def cloneScope(implicit ctx: Context): Scope = newScopeWith(this.toList: _*)
-
- /** is the scope empty? */
- override def isEmpty: Boolean = lastEntry eq null
+ def cloneScope(implicit ctx: Context): MutableScope = newScopeWith(this.toList: _*)
/** create and enter a scope entry */
protected def newScopeEntry(sym: Symbol)(implicit ctx: Context): ScopeEntry = {
@@ -100,20 +165,14 @@ object Scopes {
hashTable(i) = e
}
- /** enter a symbol
- *
- * @param sym ...
- */
- def enter[T <: Symbol](sym: T)(implicit ctx: Context): T = {
+ /** enter a symbol in this scope. */
+ final def enter[T <: Symbol](sym: T)(implicit ctx: Context): T = {
newScopeEntry(sym)
sym
}
- /** enter a symbol, asserting that no symbol with same name exists in scope
- *
- * @param sym ...
- */
- def enterUnique(sym: Symbol)(implicit ctx: Context) {
+ /** enter a symbol, asserting that no symbol with same name exists in scope */
+ final def enterUnique(sym: Symbol)(implicit ctx: Context) {
assert(lookup(sym.name) == NoSymbol, (sym.showLocated, lookup(sym.name).showLocated))
enter(sym)
}
@@ -146,7 +205,7 @@ object Scopes {
}
/** remove entry from this scope. */
- def unlink(e: ScopeEntry)(implicit ctx: Context) {
+ final def unlink(e: ScopeEntry)(implicit ctx: Context) {
if (lastEntry == e) {
lastEntry = e.prev
} else {
@@ -169,7 +228,7 @@ object Scopes {
}
/** remove symbol from this scope */
- def unlink(sym: Symbol)(implicit ctx: Context) {
+ final def unlink(sym: Symbol)(implicit ctx: Context) {
var e = lookupEntry(sym.name)
while (e ne null) {
if (e.sym == sym) unlink(e);
@@ -177,41 +236,12 @@ object Scopes {
}
}
- /** lookup a symbol
- *
- * @param name ...
- * @return ...
- */
- 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.
- */
- 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 */
- def denotsNamed(name: Name)(implicit ctx: Context): PreDenotation = {
- var syms: PreDenotation = NoDenotation
- var e = lookupEntry(name)
- while (e != null) {
- syms = syms union e.sym.denot
- e = lookupNextEntry(e)
- }
- syms
- }
-
/** lookup a symbol entry matching given name.
* @note from Martin: I believe this is a hotspot or will be one
* in future versions of the type system. I have reverted the previous
* change to use iterators as too costly.
*/
- def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = {
+ override final def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = {
var e: ScopeEntry = null
if (hashTable ne null) {
e = hashTable(name.start & (hashTable.length - 1))
@@ -228,7 +258,7 @@ object Scopes {
}
/** lookup next entry with same name as this one */
- def lookupNextEntry(entry: ScopeEntry)(implicit ctx: Context): ScopeEntry = {
+ 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.sym.name != entry.sym.name)
@@ -239,7 +269,7 @@ object Scopes {
/** Return all symbols as a list in the order they were entered in this scope.
*/
- override def toList: List[Symbol] = {
+ override final def toList: List[Symbol] = {
if (elemsCache eq null) {
elemsCache = Nil
var e = lastEntry
@@ -253,54 +283,54 @@ object Scopes {
/** Vanilla scope - symbols are stored in declaration order.
*/
- def sorted: List[Symbol] = toList
-
- /** Return all symbols as an iterator in the order they were entered in this scope.
- */
- def iterator: Iterator[Symbol] = toList.iterator
+ final def sorted: List[Symbol] = toList
override def foreach[U](p: Symbol => U): Unit = toList foreach p
- def filteredScope(p: Symbol => Boolean)(implicit ctx: Context): Scope = {
+ final def filteredScope(p: Symbol => Boolean)(implicit ctx: Context): MutableScope = {
val unfiltered = toList
val filtered = unfiltered filterConserve p
if (filtered eq unfiltered) this
else newScopeWith(filtered: _*)
}
- def show(implicit ctx: Context): String = ctx.show(this)
+ final def show(implicit ctx: Context): String = ctx.show(this)
}
/** Create a new scope */
- def newScope: Scope = 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): Scope = new Scope(outer)
+ 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): Scope = {
+ 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): Scope = newScope
+ 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: => Scope): Scope = op
+ def scopeTransform(owner: Symbol)(op: => MutableScope): MutableScope = op
/** The empty scope (immutable).
*/
object EmptyScope extends Scope {
- override def newScopeEntry(sym: Symbol)(implicit ctx: Context): ScopeEntry = {
- throw new AssertionError("EmptyScope.newScopeEntry")
- }
+ override def lastEntry = null
+ override def size = 0
+ override def nestingLevel = 0
+ override def toList = Nil
+ override def cloneScope(implicit ctx: Context): Scope = this
+ override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = null
+ override def lookupNextEntry(entry: ScopeEntry)(implicit ctx: Context): ScopeEntry = null
}
/** The error scope (mutable)
*/
- class ErrorScope(owner: Symbol) extends Scope
+ class ErrorScope(owner: Symbol) extends MutableScope
}