Added package object support to reflection framework. Removed debug output and made some speed improvements.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@25584 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
odersky 2011-08-29 17:15:56 +00:00
parent 92a40f1e57
commit a418b2e60c
11 changed files with 96 additions and 90 deletions

View File

@ -122,7 +122,45 @@ abstract class SymbolTable extends api.Universe
else noChangeInBaseClasses(infoTransformers.nextFrom(phase.id), pid)
}
}
def openPackageModule(container: Symbol, dest: Symbol) {
// unlink existing symbols in the package
for (member <- container.info.decls.iterator) {
if (!member.isPrivate && !member.isConstructor) {
// todo: handle overlapping definitions in some way: mark as errors
// or treat as abstractions. For now the symbol in the package module takes precedence.
for (existing <- dest.info.decl(member.name).alternatives)
dest.info.decls.unlink(existing)
}
}
// enter non-private decls the class
for (member <- container.info.decls.iterator) {
if (!member.isPrivate && !member.isConstructor) {
dest.info.decls.enter(member)
}
}
// enter decls of parent classes
for (pt <- container.info.parents; p = pt.typeSymbol) {
if (p != definitions.ObjectClass && p != definitions.ScalaObjectClass) {
openPackageModule(p, dest)
}
}
}
/** if there's a `package` member object in `pkgClass`, enter its members into it. */
def openPackageModule(pkgClass: Symbol) {
val pkgModule = pkgClass.info.decl(nme.PACKAGEkw)
def fromSource = pkgModule.rawInfo match {
case ltp: LazyType => ltp.fromSource
case _ => false
}
if (pkgModule.isModule && !fromSource) {
// println("open "+pkgModule)//DEBUG
openPackageModule(pkgModule, pkgClass)
}
}
object perRunCaches {
import java.lang.ref.WeakReference
import scala.runtime.ScalaRunTime.stringOf

View File

@ -2758,6 +2758,7 @@ A type's typeSymbol should never be inspected directly.
/** A class representing an as-yet unevaluated type.
*/
abstract class LazyType extends Type {
def fromSource = false
override def isComplete: Boolean = false
override def complete(sym: Symbol)
override def safeToString = "<?>"

View File

@ -51,13 +51,12 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
else "error while loading " + clazz.name + ", " + msg)
}
try {
println("unpickling " + clazz + " " + module) //debug
info("unpickling " + clazz + " " + module) //debug
markAbsent(NoType)
val ssig = jclazz.getAnnotation(classOf[scala.reflect.ScalaSignature])
if (ssig != null) {
val bytes = ssig.bytes.getBytes
val len = ByteCodecs.decode(bytes)
println("short sig:" + len)
unpickler.unpickle(bytes take len, 0, clazz, module, jclazz.getName)
} else {
val slsig = jclazz.getAnnotation(classOf[scala.reflect.ScalaLongSignature])
@ -70,10 +69,9 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
bs.copyToArray(bytes, len, l)
len += l
}
println("long sig") //debug
unpickler.unpickle(bytes, 0, clazz, module, jclazz.getName)
} else { // class does not have a Scala signature; it's a Java class
println("no sig found for " + jclazz) //debug
info("no sig found for " + jclazz) //debug
initClassModule(clazz, module, new FromJavaClassCompleter(clazz, module, jclazz))
}
}
@ -127,7 +125,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
*/
private class FromJavaClassCompleter(clazz: Symbol, module: Symbol, jclazz: jClass[_]) extends LazyType {
override def complete(sym: Symbol) = {
println("completing from Java " + sym + "/" + clazz.fullName)//debug
info("completing from Java " + sym + "/" + clazz.fullName)//debug
assert(sym == clazz || sym == module || sym == module.moduleClass, sym)
val flags = toScalaFlags(jclazz.getModifiers, isClass = true)
clazz setFlag (flags | JAVA)
@ -288,7 +286,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
var pkg = owner.info decl name
if (pkg == NoSymbol) {
pkg = owner.newPackage(NoPosition, name)
pkg.moduleClass setInfo newPackageType(pkg.moduleClass)
pkg.moduleClass setInfo new LazyPackageType
pkg setInfo typeRef(pkg.owner.thisType, pkg.moduleClass, Nil)
owner.info.decls enter pkg
} else if (!pkg.isPackage)

View File

@ -2,15 +2,15 @@ package scala.reflect
package runtime
import internal.Flags
import java.lang.{Class => jClass, Package => jPackage}
import collection.mutable
trait Loaders { self: SymbolTable =>
/** The lazy type for root.
*/
override val rootLoader = new LazyType {
override def complete(sym: Symbol) = sym setInfo newPackageType(definitions.RootClass)
override def complete(sym: Symbol) = sym setInfo new LazyPackageType
}
/** The standard completer for top-level classes
@ -21,34 +21,33 @@ trait Loaders { self: SymbolTable =>
* is found, a package is created instead.
*/
class TopClassCompleter(clazz: Symbol, module: Symbol) extends LazyType {
def makePackage() {
println("wrong guess; making package "+clazz)
val ptpe = newPackageType(module.moduleClass)
for (sym <- List(clazz, module, module.moduleClass)) {
sym setFlag Flags.PACKAGE
sym setInfo ptpe
}
}
// def makePackage() {
// println("wrong guess; making package "+clazz)
// val ptpe = newPackageType(module.moduleClass)
// for (sym <- List(clazz, module, module.moduleClass)) {
// sym setFlag Flags.PACKAGE
// sym setInfo ptpe
// }
// }
override def complete(sym: Symbol) = {
println("completing "+sym+"/"+clazz.fullName+
(if (sym == clazz) 1 else if (sym == module) 2 else if (sym == module.moduleClass) 3 else 4)) //debug
info("completing "+sym+"/"+clazz.fullName)
assert(sym == clazz || sym == module || sym == module.moduleClass)
try {
unpickleClass(clazz, module, jClass.forName(clazz.fullName))
} catch {
case ex: ClassNotFoundException => makePackage()
case ex: NoClassDefFoundError => makePackage()
// try {
unpickleClass(clazz, module, jClass.forName(clazz.fullName))
// } catch {
// case ex: ClassNotFoundException => makePackage()
// case ex: NoClassDefFoundError => makePackage()
// Note: We catch NoClassDefFoundError because there are situations
// where a package and a class have the same name except for capitalization.
// It seems in this case the class is loaded even if capitalization differs
// but then a NoClassDefFound error is issued with a ("wrong name: ...")
// reason. (I guess this is a concession to Windows).
// The present behavior is a bit too forgiving, in that it masks
// all class loade errors, not just wrong name errors. We should try
// all class load errors, not just wrong name errors. We should try
// to be more discriminating. To get on the right track simply delete
// the clause above and load a collection class such as collection.Iterable.
// You'll see an error that class `parallel` has the wrong name.
}
// }
}
}
@ -74,43 +73,34 @@ trait Loaders { self: SymbolTable =>
module.moduleClass.setInfo(completer)
}
/** The type for packages.
* Since we cannot search the file system for classes in directories to populate
* a package, we do the following instead: For every member that is looked up in
* the package, create a class and companion object optimistically, giving it
* a TopClassCompleter type. When any of the two symbols is forced via info,
* the TopClassCompleter will sort things out.
/** The type completer for packages.
*/
def newPackageType(pkgClass: Symbol) = new ClassInfoType(List(), new PackageScope(pkgClass), pkgClass) {
/*
override def decl(name: Name): Symbol =
(decls lookup name) orElse {
assert(this eq pkg.info, this+" "+pkg.info)
assert(decls eq pkg.info.decls)
//println("creating "+name+" in "+pkg) //debug
val (clazz, module) = createClassModule(pkg, name.toTypeName, new TopClassCompleter(_, _))
if (name.isTypeName) clazz else module
}
override def member(name: Name): Symbol = decl(name)
override def findMember(name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean) =
member(name).filter (m => m.hasAllFlags(requiredFlags) && !m.hasFlag(excludedFlags))
*/
override def safeToString = pkgClass.toString
class LazyPackageType extends LazyType {
override def complete(sym: Symbol) {
assert(sym.isPackageClass)
sym setInfo new ClassInfoType(List(), new PackageScope(sym), sym)
// override def safeToString = pkgClass.toString
openPackageModule(sym)
}
}
class PackageScope(pkgClass: Symbol) extends Scope {
private var negatives = mutable.Set[Name]()
override def lookupEntry(name: Name): ScopeEntry = {
val e = super.lookupEntry(name)
if (e != null)
e
else if (negatives contains name)
null
else try {
jClass.forName(pkgClass.fullName + "." + name)
val (clazz, module) = createClassModule(pkgClass, name.toTypeName, new TopClassCompleter(_, _))
println("created "+module+"/"+module.moduleClass+" in "+pkgClass+", scope = "+(this map (_.name)))
info("created "+module+"/"+module.moduleClass+" in "+pkgClass+", scope = "+(this map (_.name)))
lookupEntry(name)
} catch {
case ex: ClassNotFoundException =>
println("not found : "+pkgClass.fullName + "." + name)
case (_: ClassNotFoundException) | (_: NoClassDefFoundError) =>
info("*** not found : "+pkgClass.fullName + "." + name)
negatives += name
null
}
}

View File

@ -72,7 +72,7 @@ object Mirror extends Mirror
/** test code; should go to tests once things settle down a bit
*
*/
object Test extends Mirror with App {
val sym = classToScala(classOf[scala.collection.Iterable[_]])
println(sym)
@ -81,3 +81,4 @@ object Test extends Mirror with App {
val ms = sym.info.members.toList map (_.initialize)
println("members = "+(ms map (_.defString) mkString ("\n ")))
}
*/

View File

@ -15,7 +15,7 @@ trait SymbolTable extends internal.SymbolTable with JavaToScala with ScalaToJava
if (name.isTermName && owner.hasPackageFlag)
makeScalaPackage(if (owner.isRoot) name.toString else owner.fullName+"."+name).sourceModule
else {
println(name+"/"+name.isTermName+"/"+owner+"/"+owner.hasPackageFlag+"/"+owner.info.decls.getClass)
info("*** missing: "+name+"/"+name.isTermName+"/"+owner+"/"+owner.hasPackageFlag+"/"+owner.info.decls.getClass)
super.missingHook(owner, name)
}
@ -23,4 +23,9 @@ trait SymbolTable extends internal.SymbolTable with JavaToScala with ScalaToJava
override def validateClassInfo(tp: ClassInfoType) {
assert(!tp.typeSymbol.isPackageClass || tp.decls.isInstanceOf[PackageScope])
}
protected var verbose = false
def info(msg: => String) =
if (verbose) println("[reflect-compiler] "+msg)
}

View File

@ -84,7 +84,7 @@ abstract class BrowsingLoaders extends SymbolLoaders {
entered += 1
if (name == nme.PACKAGEkw) {
println("open package module: "+module)
loaders.openPackageModule(module)()
openPackageModule(module, root)
}
} else println("prefixes differ: "+packagePrefix+","+root.fullName)
case _ =>

View File

@ -230,37 +230,8 @@ abstract class SymbolLoaders {
for (pkg <- classpath.packages) {
enterPackage(root, pkg.name, newPackageLoader(pkg))
}
// if there's a $member object, enter its members as well.
val pkgModule = root.info.decl(nme.PACKAGEkw)
if (pkgModule.isModule && !pkgModule.rawInfo.isInstanceOf[SourcefileLoader]) {
// println("open "+pkgModule)//DEBUG
openPackageModule(pkgModule)()
}
}
}
def openPackageModule(module: Symbol)(packageClass: Symbol = module.owner): Unit = {
// unlink existing symbols in the package
for (member <- module.info.decls.iterator) {
if (!member.isPrivate && !member.isConstructor) {
// todo: handle overlapping definitions in some way: mark as errors
// or treat as abstractions. For now the symbol in the package module takes precedence.
for (existing <- packageClass.info.decl(member.name).alternatives)
packageClass.info.decls.unlink(existing)
}
}
// enter non-private decls the class
for (member <- module.info.decls.iterator) {
if (!member.isPrivate && !member.isConstructor) {
packageClass.info.decls.enter(member)
}
}
// enter decls of parent classes
for (pt <- module.info.parents; p = pt.typeSymbol) {
if (p != definitions.ObjectClass && p != definitions.ScalaObjectClass) {
openPackageModule(p)(packageClass)
}
openPackageModule(root)
}
}
@ -328,6 +299,7 @@ abstract class SymbolLoaders {
class SourcefileLoader(val srcfile: AbstractFile) extends SymbolLoader {
protected def description = "source file "+ srcfile.toString
override def fromSource = true
override def sourcefile = Some(srcfile)
protected def doComplete(root: Symbol): Unit = global.currentRun.compileLate(srcfile)
}

View File

@ -55,7 +55,7 @@ trait Analyzer extends AnyRef
override def traverse(tree: Tree): Unit = tree match {
case ModuleDef(_, _, _) =>
if (tree.symbol.name == nme.PACKAGEkw) {
loaders.openPackageModule(tree.symbol)()
openPackageModule(tree.symbol, tree.symbol.owner)
}
case ClassDef(_, _, _, _) => () // make it fast
case _ => super.traverse(tree)

View File

@ -191,8 +191,9 @@ trait Namers { self: Analyzer =>
var pkg = owner.info.decls.lookup(pid.name)
if (!pkg.isPackage || owner != pkg.owner) {
pkg = owner.newPackage(pos, pid.name.toTermName)
pkg.moduleClass.setInfo(new PackageClassInfoType(new Scope, pkg.moduleClass))
pkg.setInfo(pkg.moduleClass.tpe)
val pkgClass = pkg.moduleClass
pkgClass.setInfo(new PackageClassInfoType(newPackageScope(pkgClass), pkgClass))
pkg.setInfo(pkgClass.tpe)
enterInScope(pkg, owner.info.decls)
}
pkg

View File

@ -35,6 +35,6 @@ object Test {
val thickness = 2
val color = 0
}
scala.Console.println(bcs1 == bcs1)
scala.Console.println(bcs1 == bcs2)
Console.println(bcs1 == bcs1)
Console.println(bcs1 == bcs2)
}