aboutsummaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala2
-rw-r--r--src/dotty/tools/dotc/core/Scopes.scala168
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala4
-rw-r--r--src/dotty/tools/dotc/core/SymbolLoaders.scala4
-rw-r--r--src/dotty/tools/dotc/core/Symbols.scala2
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala2
-rw-r--r--src/dotty/tools/dotc/core/pickling/ClassfileParser.scala6
-rw-r--r--src/dotty/tools/dotc/core/pickling/UnPickler.scala6
8 files changed, 112 insertions, 82 deletions
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 4af1fefa4..878cec877 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -25,7 +25,7 @@ class Definitions(implicit ctx: Context) {
import ctx.{requiredClass, requiredModule, requiredPackage}
- private def newSyntheticTypeParam(cls: ClassSymbol, scope: Scope, suffix: String = "T0") = {
+ private def newSyntheticTypeParam(cls: ClassSymbol, scope: MutableScope, suffix: String = "T0") = {
val tname = suffix.toTypeName.expandedName(cls)
val tparam = ctx.newSymbol(cls, tname, TypeParamCreationFlags, TypeBounds.empty)
scope.enter(tparam)
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
}
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 975c4d6f1..144432245 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -722,7 +722,7 @@ object SymDenotations {
*/
def enter(sym: Symbol)(implicit ctx: Context) = {
require(!(this is Frozen))
- info.decls enter sym
+ info.decls.openForMutations.enter(sym)
if (_definedFingerPrint != null)
includeName(_definedFingerPrint, sym.name)
if (_memberCache != null)
@@ -735,7 +735,7 @@ object SymDenotations {
*/
def delete(sym: Symbol)(implicit ctx: Context) = {
require(!(this is Frozen))
- info.decls unlink sym
+ info.decls.openForMutations.unlink(sym)
if (_definedFingerPrint != null)
computeDefinedFingerPrint
if (_memberCache != null)
diff --git a/src/dotty/tools/dotc/core/SymbolLoaders.scala b/src/dotty/tools/dotc/core/SymbolLoaders.scala
index 59835beda..9559db68a 100644
--- a/src/dotty/tools/dotc/core/SymbolLoaders.scala
+++ b/src/dotty/tools/dotc/core/SymbolLoaders.scala
@@ -20,7 +20,7 @@ class SymbolLoaders {
protected def enterIfNew(owner: Symbol, member: Symbol, completer: SymbolLoader)(implicit ctx: Context): Symbol = {
assert(owner.info.decls.lookup(member.name) == NoSymbol, owner.fullName + "." + member.name)
- owner.info.decls enter member
+ owner.asClass.enter(member)
member
}
@@ -57,7 +57,7 @@ class SymbolLoaders {
else if (ctx.settings.termConflict.value == "package") {
ctx.warning(
s"Resolving package/object name conflict in favor of package ${preExisting.fullName}. The object will be inaccessible.")
- owner.info.decls.unlink(preExisting)
+ owner.asClass.delete(preExisting)
} else {
ctx.warning(
s"Resolving package/object name conflict in favor of object ${preExisting.fullName}. The package will be inaccessible.")
diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala
index 2491e2ff9..90b9837ca 100644
--- a/src/dotty/tools/dotc/core/Symbols.scala
+++ b/src/dotty/tools/dotc/core/Symbols.scala
@@ -318,7 +318,7 @@ object Symbols {
def superId: Int = -1
final def entered(implicit ctx: Context): this.type = {
- this.owner.info.decls.enter(this)
+ this.owner.asClass.enter(this)
this
}
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index a8c9af32d..6628aa824 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -197,7 +197,7 @@ trait TypeOps { this: Context =>
* to a list of typerefs, by converting all refinements to member
* definitions in scope `decls`. Can add members to `decls` as a side-effect.
*/
- def normalizeToRefs(parents: List[Type], cls: ClassSymbol, decls: Scope): List[TypeRef] = {
+ def normalizeToRefs(parents: List[Type], cls: ClassSymbol, decls: MutableScope): List[TypeRef] = {
var refinements = Map[TypeName, Type]()
var formals = Map[TypeName, Symbol]()
def normalizeToRef(tp: Type): TypeRef = tp match {
diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
index 685ece6cb..5fbafb431 100644
--- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
+++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
@@ -26,8 +26,8 @@ class ClassfileParser(
protected val staticModule: Symbol = moduleRoot.sourceModule
- protected val instanceScope: Scope = newScope // the scope of all instance definitions
- protected val staticScope: Scope = newScope // the scope of all static definitions
+ protected val instanceScope: MutableScope = newScope // the scope of all instance definitions
+ protected val staticScope: MutableScope = newScope // the scope of all static definitions
protected var pool: ConstantPool = _ // the classfile's constant pool
protected var currentClassName: Name = _ // JVM name of the current class
@@ -707,7 +707,7 @@ class ClassfileParser(
protected def getOwner(flags: Int): Symbol =
if (isStatic(flags)) moduleRoot.symbol else classRoot.symbol
- protected def getScope(flags: Int): Scope =
+ protected def getScope(flags: Int): MutableScope =
if (isStatic(flags)) staticScope else instanceScope
private def setPrivateWithin(denot: SymDenotation, jflags: Int) {
diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
index 9edc8cb84..55ed9b63d 100644
--- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala
+++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
@@ -24,7 +24,7 @@ object UnPickler {
case class TempPolyType(tparams: List[Symbol], tpe: Type) extends UncachedGroundType
/** Temporary type for classinfos, will be decomposed on completion of the class */
- case class TempClassInfoType(parentTypes: List[Type], decls: Scope, clazz: Symbol) extends UncachedGroundType
+ case class TempClassInfoType(parentTypes: List[Type], decls: MutableScope, clazz: Symbol) extends UncachedGroundType
def depoly(tp: Type)(implicit ctx: Context): Type = tp match {
case TempPolyType(tparams, restpe) => PolyType.fromSymbols(tparams, restpe)
@@ -356,7 +356,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleRoot: Clas
isUnpickleRoot(sym) ||
(sym is (ModuleClass | TypeParam | Scala2Existential)) ||
isRefinementClass(sym)))
- symScope(sym.owner) enter sym
+ symScope(sym.owner).openForMutations.enter(sym)
sym
}
@@ -519,7 +519,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleRoot: Clas
}
case CLASSINFOtpe =>
val clazz = readSymbolRef()
- TempClassInfoType(until(end, readTypeRef), symScope(clazz), clazz)
+ TempClassInfoType(until(end, readTypeRef), symScope(clazz).openForMutations, clazz)
case METHODtpe | IMPLICITMETHODtpe =>
val restpe = readTypeRef()
val params = until(end, readSymbolRef)