summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-11-01 13:01:02 -0700
committerPaul Phillips <paulp@improving.org>2012-11-02 00:08:01 -0700
commitd7ed53f26d6466109cd5828008a8ba2026d95238 (patch)
treee39d9e9a659f42622ef810b26661d5a844a09087 /src
parent64258cf019fb7ebfd9a78451236dac9c676f120b (diff)
downloadscala-d7ed53f26d6466109cd5828008a8ba2026d95238.tar.gz
scala-d7ed53f26d6466109cd5828008a8ba2026d95238.tar.bz2
scala-d7ed53f26d6466109cd5828008a8ba2026d95238.zip
Hardening scope lookup against wrongness.
Calls to scope.lookup have until this commit discarded any symbols after the first, even at the same nesting depth. Some call sites which did this were innocuous, because they were only checking if lookup(name) != NoSymbol. To make this clearer in the future, I added a method which communicates the intent: containsName. And I added an even more relevant one, which falls between "lookup" and "lookupAll". def lookupUnshadowedEntries(name: Name) That method will be put to work in symbol lookup, allowing us to put to bed methods like "correctForPackageObject".
Diffstat (limited to 'src')
-rw-r--r--src/reflect/scala/reflect/internal/Scopes.scala60
1 files changed, 53 insertions, 7 deletions
diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala
index a4b541e34d..352bc8fdc9 100644
--- a/src/reflect/scala/reflect/internal/Scopes.scala
+++ b/src/reflect/scala/reflect/internal/Scopes.scala
@@ -25,8 +25,9 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
*/
var next: ScopeEntry = null
+ def depth = owner.nestingLevel
override def hashCode(): Int = sym.name.start
- override def toString(): String = sym.toString()
+ override def toString() = s"$sym (depth=$depth)"
}
/**
@@ -216,14 +217,46 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
}
}
- /** lookup a symbol
- *
- * @param name ...
- * @return ...
+ /** Lookup a module or a class, filtering out matching names in scope
+ * which do not match that requirement.
+ */
+ def lookupModule(name: Name): Symbol = lookupAll(name.toTermName) find (_.isModule) getOrElse NoSymbol
+ def lookupClass(name: Name): Symbol = lookupAll(name.toTypeName) find (_.isClass) getOrElse NoSymbol
+
+ /** True if the name exists in this scope, false otherwise. */
+ def containsName(name: Name) = lookupEntry(name) != null
+
+ /** Lookup a symbol.
*/
def lookup(name: Name): Symbol = {
val e = lookupEntry(name)
- if (e eq null) NoSymbol else e.sym
+ if (e eq null) NoSymbol
+ else if (lookupNextEntry(e) eq null) e.sym
+ else {
+ // We shouldn't get here: until now this method was picking a random
+ // symbol when there was more than one with the name, so this should
+ // only be called knowing that there are 0-1 symbols of interest. So, we
+ // can safely return an overloaded symbol rather than throwing away the
+ // rest of them. Most likely we still break, but at least we will break
+ // in an understandable fashion (unexpectedly overloaded symbol) rather
+ // than a non-deterministic bizarre one (see any bug involving overloads
+ // in package objects.)
+ val alts = lookupAll(name).toList
+ log("!!! scope lookup of $name found multiple symbols: $alts")
+ // FIXME - how is one supposed to create an overloaded symbol without
+ // knowing the correct owner? Using the symbol owner is not correct;
+ // say for instance this is List's scope and the symbols are its three
+ // mkString members. Those symbols are owned by TraversableLike, which
+ // is no more meaningful an owner than NoSymbol given that we're in
+ // List. Maybe it makes no difference who owns the overloaded symbol, in
+ // which case let's establish that and have a canonical creation method.
+ //
+ // FIXME - a similar question for prefix, although there are more
+ // clues from the symbols on that one, as implemented here. In general
+ // the distinct list is one type and lub becomes the identity.
+ val prefix = lub(alts map (_.info.prefix) distinct)
+ NoSymbol.newOverloaded(prefix, alts)
+ }
}
/** Returns an iterator yielding every symbol with given name in this scope.
@@ -231,7 +264,20 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
def lookupAll(name: Name): 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 }
+ def next(): Symbol = try e.sym finally e = lookupNextEntry(e)
+ }
+
+ def lookupAllEntries(name: Name): Iterator[ScopeEntry] = new Iterator[ScopeEntry] {
+ var e = lookupEntry(name)
+ def hasNext: Boolean = e ne null
+ def next(): ScopeEntry = try e finally e = lookupNextEntry(e)
+ }
+
+ def lookupUnshadowedEntries(name: Name): Iterator[ScopeEntry] = {
+ lookupEntry(name) match {
+ case null => Iterator.empty
+ case e => lookupAllEntries(name) filter (e1 => (e eq e1) || (e.depth == e1.depth && e.sym != e1.sym))
+ }
}
/** lookup a symbol entry matching given name.