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:
parent
92a40f1e57
commit
a418b2e60c
|
@ -123,6 +123,44 @@ abstract class SymbolTable extends api.Universe
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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 = "<?>"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
// try {
|
||||
unpickleClass(clazz, module, jClass.forName(clazz.fullName))
|
||||
} catch {
|
||||
case ex: ClassNotFoundException => makePackage()
|
||||
case ex: NoClassDefFoundError => makePackage()
|
||||
// } 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
|
||||
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)
|
||||
}
|
||||
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 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ")))
|
||||
}
|
||||
*/
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 _ =>
|
||||
|
|
|
@ -231,36 +231,7 @@ abstract class SymbolLoaders {
|
|||
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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue