From a418b2e60cd17be6e002e2b1767861191d7482da Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 29 Aug 2011 17:15:56 +0000 Subject: [PATCH] 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 --- .../scala/reflect/internal/SymbolTable.scala | 40 +++++++++- .../scala/reflect/internal/Types.scala | 1 + .../scala/reflect/runtime/JavaToScala.scala | 10 +-- .../scala/reflect/runtime/Loaders.scala | 78 ++++++++----------- .../scala/reflect/runtime/Mirror.scala | 3 +- .../scala/reflect/runtime/SymbolTable.scala | 7 +- .../tools/nsc/symtab/BrowsingLoaders.scala | 2 +- .../tools/nsc/symtab/SymbolLoaders.scala | 34 +------- .../tools/nsc/typechecker/Analyzer.scala | 2 +- .../scala/tools/nsc/typechecker/Namers.scala | 5 +- test/files/pos/traits.scala | 4 +- 11 files changed, 96 insertions(+), 90 deletions(-) diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index 63a94a648..228c4491f 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -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 diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 82e42c112..5913b7c51 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -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 = "" diff --git a/src/compiler/scala/reflect/runtime/JavaToScala.scala b/src/compiler/scala/reflect/runtime/JavaToScala.scala index 078f4e31f..7a6785ae9 100644 --- a/src/compiler/scala/reflect/runtime/JavaToScala.scala +++ b/src/compiler/scala/reflect/runtime/JavaToScala.scala @@ -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) diff --git a/src/compiler/scala/reflect/runtime/Loaders.scala b/src/compiler/scala/reflect/runtime/Loaders.scala index e4bbd5d2d..310195bcd 100644 --- a/src/compiler/scala/reflect/runtime/Loaders.scala +++ b/src/compiler/scala/reflect/runtime/Loaders.scala @@ -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 } } diff --git a/src/compiler/scala/reflect/runtime/Mirror.scala b/src/compiler/scala/reflect/runtime/Mirror.scala index e01a7da6d..2cb1069df 100644 --- a/src/compiler/scala/reflect/runtime/Mirror.scala +++ b/src/compiler/scala/reflect/runtime/Mirror.scala @@ -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 "))) } +*/ \ No newline at end of file diff --git a/src/compiler/scala/reflect/runtime/SymbolTable.scala b/src/compiler/scala/reflect/runtime/SymbolTable.scala index a88465e93..2f12a2df6 100644 --- a/src/compiler/scala/reflect/runtime/SymbolTable.scala +++ b/src/compiler/scala/reflect/runtime/SymbolTable.scala @@ -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) } diff --git a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala index 115bad8bc..7fea0ed11 100644 --- a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala @@ -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 _ => diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index fbc1bc7cc..be76acda1 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -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) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala index 0b6ec17a7..844a5014a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala @@ -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) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 7917f3be1..7537bb36d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -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 diff --git a/test/files/pos/traits.scala b/test/files/pos/traits.scala index 04f1d6b23..bd64d7215 100644 --- a/test/files/pos/traits.scala +++ b/test/files/pos/traits.scala @@ -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) }