More refinements to reflection and the reflective compiler.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@25611 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
odersky 2011-09-05 10:44:04 +00:00
parent 0a74d04a58
commit daaa644d6b
14 changed files with 78 additions and 56 deletions

View File

@ -670,11 +670,11 @@ trait Definitions extends reflect.api.StandardDefinitions {
else { else {
if (settings.debug.value) { log(sym.info); log(sym.info.members) }//debug if (settings.debug.value) { log(sym.info); log(sym.info.members) }//debug
missingHook(owner, name) orElse { missingHook(owner, name) orElse {
throw new MissingRequirementError((if (path.isTermName) "object " else "class ")+path) MissingRequirementError.notFound((if (path.isTermName) "object " else "class ")+path)
} }
} }
} }
/** If you're looking for a class, pass a type name. /** If you're looking for a class, pass a type name.
* If a module, a term name. * If a module, a term name.
*/ */

View File

@ -6,12 +6,18 @@
package scala.reflect package scala.reflect
package internal package internal
class MissingRequirementError(val req: String) extends FatalError(req + " not found.") class MissingRequirementError private (msg: String) extends FatalError(msg) {
import MissingRequirementError.suffix
def req: String = if (msg endsWith suffix) msg dropRight suffix.length else msg
}
object MissingRequirementError { object MissingRequirementError {
private val suffix = " not found."
def signal(msg: String): Nothing = throw new MissingRequirementError(msg)
def notFound(req: String): Nothing = signal(req + suffix)
def unapply(x: Throwable) = x match { def unapply(x: Throwable) = x match {
case x: MissingRequirementError => Some(x.req) case x: MissingRequirementError => x.req
case _ => None case _ => None
} }
} }

View File

@ -147,12 +147,37 @@ abstract class SymbolTable extends api.Universe
} }
} }
/** Convert array parameters denoting a repeated parameter of a Java method
* to `JavaRepeatedParamClass` types.
*/
def arrayToRepeated(tp: Type): Type = tp match {
case MethodType(params, rtpe) =>
val formals = tp.paramTypes
assert(formals.last.typeSymbol == definitions.ArrayClass)
val method = params.last.owner
val elemtp = formals.last.typeArgs.head match {
case RefinedType(List(t1, t2), _) if (t1.typeSymbol.isAbstractType && t2.typeSymbol == definitions.ObjectClass) =>
t1 // drop intersection with Object for abstract types in varargs. UnCurry can handle them.
case t =>
t
}
val newParams = method.newSyntheticValueParams(
formals.init :+ appliedType(definitions.JavaRepeatedParamClass.typeConstructor, List(elemtp)))
MethodType(newParams, rtpe)
case PolyType(tparams, rtpe) =>
PolyType(tparams, arrayToRepeated(rtpe))
}
abstract class SymLoader extends LazyType {
def fromSource = false
}
/** if there's a `package` member object in `pkgClass`, enter its members into it. */ /** if there's a `package` member object in `pkgClass`, enter its members into it. */
def openPackageModule(pkgClass: Symbol) { def openPackageModule(pkgClass: Symbol) {
val pkgModule = pkgClass.info.decl(nme.PACKAGEkw) val pkgModule = pkgClass.info.decl(nme.PACKAGEkw)
def fromSource = pkgModule.rawInfo match { def fromSource = pkgModule.rawInfo match {
case ltp: LazyType => ltp.fromSource case ltp: SymLoader => ltp.fromSource
case _ => false case _ => false
} }
if (pkgModule.isModule && !fromSource) { if (pkgModule.isModule && !fromSource) {

View File

@ -1817,7 +1817,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/ */
override def toString = compose( override def toString = compose(
kindString, kindString,
if (hasMeaninglessName) owner.nameString else nameString if (hasMeaninglessName) owner.decodedName + idString else nameString
) )
/** String representation of location. /** String representation of location.

View File

@ -1146,6 +1146,7 @@ trait Types extends api.Types { self: SymbolTable =>
/** A class for this-types of the form <sym>.this.type /** A class for this-types of the form <sym>.this.type
*/ */
abstract case class ThisType(sym: Symbol) extends SingletonType { abstract case class ThisType(sym: Symbol) extends SingletonType {
assert(sym.isClass)
//assert(sym.isClass && !sym.isModuleClass || sym.isRoot, sym) //assert(sym.isClass && !sym.isModuleClass || sym.isRoot, sym)
override def isTrivial: Boolean = sym.isPackageClass override def isTrivial: Boolean = sym.isPackageClass
override def isNotNull = true override def isNotNull = true
@ -2759,7 +2760,6 @@ A type's typeSymbol should never be inspected directly.
/** A class representing an as-yet unevaluated type. /** A class representing an as-yet unevaluated type.
*/ */
abstract class LazyType extends Type { abstract class LazyType extends Type {
def fromSource = false
override def isComplete: Boolean = false override def isComplete: Boolean = false
override def complete(sym: Symbol) override def complete(sym: Symbol)
override def safeToString = "<?>" override def safeToString = "<?>"

View File

@ -195,12 +195,12 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ {
val name = readNameRef() val name = readNameRef()
val owner = if (atEnd) definitions.RootClass else readSymbolRef() val owner = if (atEnd) definitions.RootClass else readSymbolRef()
def adjust(sym: Symbol) = if (tag == EXTref) sym else sym.moduleClass
def fromName(name: Name) = name.toTermName match { def fromName(name: Name) = name.toTermName match {
case nme.ROOT => definitions.RootClass case nme.ROOT => definitions.RootClass
case nme.ROOTPKG => definitions.RootPackage case nme.ROOTPKG => definitions.RootPackage
case _ => case _ => adjust(owner.info.decl(name))
val s = owner.info.decl(name)
if (tag == EXTref) s else s.moduleClass
} }
def nestedObjectSymbol: Symbol = { def nestedObjectSymbol: Symbol = {
// If the owner is overloaded (i.e. a method), it's not possible to select the // If the owner is overloaded (i.e. a method), it's not possible to select the
@ -227,7 +227,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ {
// (3) Try as a nested object symbol. // (3) Try as a nested object symbol.
nestedObjectSymbol orElse { nestedObjectSymbol orElse {
// (4) Otherwise, fail. // (4) Otherwise, fail.
errorMissingRequirement(name, owner) adjust(errorMissingRequirement(name, owner))
} }
} }
} }
@ -819,9 +819,9 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ {
protected def errorMissingRequirement(name: Name, owner: Symbol): Symbol = protected def errorMissingRequirement(name: Name, owner: Symbol): Symbol =
missingHook(owner, name) orElse { missingHook(owner, name) orElse {
throw new MissingRequirementError( MissingRequirementError.notFound(
"reference " + (if (name.isTypeName) "type " else "value ") + "reference " + (if (name.isTypeName) "type " else "value ") +
name.decode + " of " + owner.tpe.widen) name.decode + " of " + owner.tpe.widen + "/" +owner.tpe.typeSymbol.ownerChain)
} }
def inferMethodAlternative(fun: Tree, argtpes: List[Type], restpe: Type) {} // can't do it; need a compiler for that. def inferMethodAlternative(fun: Tree, argtpes: List[Type], restpe: Type) {} // can't do it; need a compiler for that.

View File

@ -47,9 +47,9 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
markAbsent(ErrorType) markAbsent(ErrorType)
if (settings.debug.value) ex.printStackTrace() if (settings.debug.value) ex.printStackTrace()
val msg = ex.getMessage() val msg = ex.getMessage()
throw new MissingRequirementError( MissingRequirementError.signal(
if (msg eq null) "reflection error while loading " + clazz.name (if (msg eq null) "reflection error while loading " + clazz.name
else "error while loading " + clazz.name + ", " + msg) else "error while loading " + clazz.name) + ", " + msg)
} }
try { try {
info("unpickling " + clazz + " " + module) //debug info("unpickling " + clazz + " " + module) //debug
@ -145,6 +145,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
module.moduleClass setInfo new LazyPolyType(List()) module.moduleClass setInfo new LazyPolyType(List())
} }
} }
override def complete(sym: Symbol): Unit = { override def complete(sym: Symbol): Unit = {
load(sym) load(sym)
completeRest() completeRest()
@ -168,14 +169,12 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
def enter(sym: Symbol, mods: Int) = def enter(sym: Symbol, mods: Int) =
(if (jModifier.isStatic(mods)) module.moduleClass else clazz).info.decls enter sym (if (jModifier.isStatic(mods)) module.moduleClass else clazz).info.decls enter sym
pendingLoadActions = { () => for (jinner <- jclazz.getDeclaredClasses) {
println("... entering "+jinner)
enter(jclassAsScala(jinner, clazz), jinner.getModifiers)
}
println("entering members of "+jclazz) pendingLoadActions = { () =>
for (jinner <- jclazz.getDeclaredClasses) {
println("... entering "+jinner)
enter(jclassAsScala(jinner, clazz), jinner.getModifiers)
}
for (jfield <- jclazz.getDeclaredFields) for (jfield <- jclazz.getDeclaredFields)
enter(jfieldAsScala(jfield), jfield.getModifiers) enter(jfieldAsScala(jfield), jfield.getModifiers)
@ -475,6 +474,9 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
val resulttpe = typeToScala(jmeth.getGenericReturnType) val resulttpe = typeToScala(jmeth.getGenericReturnType)
setMethType(meth, tparams, paramtpes, resulttpe) setMethType(meth, tparams, paramtpes, resulttpe)
copyAnnotations(meth, jmeth) copyAnnotations(meth, jmeth)
if ((jmeth.getModifiers & JAVA_ACC_VARARGS) != 0) {
meth.setInfo(arrayToRepeated(meth.info))
}
meth meth
} }

View File

@ -20,7 +20,7 @@ trait Loaders { self: SymbolTable =>
* by unpickling information from the corresponding Java class. If no Java class * by unpickling information from the corresponding Java class. If no Java class
* is found, a package is created instead. * is found, a package is created instead.
*/ */
class TopClassCompleter(clazz: Symbol, module: Symbol) extends LazyType { class TopClassCompleter(clazz: Symbol, module: Symbol) extends SymLoader {
// def makePackage() { // def makePackage() {
// println("wrong guess; making package "+clazz) // println("wrong guess; making package "+clazz)
// val ptpe = newPackageType(module.moduleClass) // val ptpe = newPackageType(module.moduleClass)
@ -85,18 +85,24 @@ trait Loaders { self: SymbolTable =>
} }
} }
def invalidClassName(name: Name) = {
val dp = name pos '$'
0 < dp && dp < (name.length - 1)
}
class PackageScope(pkgClass: Symbol) extends Scope { class PackageScope(pkgClass: Symbol) extends Scope {
assert(pkgClass.isType)
private var negatives = mutable.Set[Name]() private var negatives = mutable.Set[Name]()
override def lookupEntry(name: Name): ScopeEntry = { override def lookupEntry(name: Name): ScopeEntry = {
val e = super.lookupEntry(name) val e = super.lookupEntry(name)
if (e != null) if (e != null)
e e
else if (negatives contains name) else if (invalidClassName(name) || (negatives contains name))
null null
else try { else try {
jClass.forName(pkgClass.fullName + "." + name) jClass.forName(pkgClass.fullName + "." + name)
val (clazz, module) = createClassModule(pkgClass, name.toTypeName, new TopClassCompleter(_, _)) val (clazz, module) = createClassModule(pkgClass, name.toTypeName, new TopClassCompleter(_, _))
info("created "+module+"/"+module.moduleClass+" in "+pkgClass+", scope = "+(this map (_.name))) info("created "+module+"/"+module.moduleClass+" in "+pkgClass)
lookupEntry(name) lookupEntry(name)
} catch { } catch {
case (_: ClassNotFoundException) | (_: NoClassDefFoundError) => case (_: ClassNotFoundException) | (_: NoClassDefFoundError) =>

View File

@ -23,9 +23,7 @@ trait SymbolTable extends internal.SymbolTable with JavaToScala with ScalaToJava
override def validateClassInfo(tp: ClassInfoType) { override def validateClassInfo(tp: ClassInfoType) {
assert(!tp.typeSymbol.isPackageClass || tp.decls.isInstanceOf[PackageScope]) assert(!tp.typeSymbol.isPackageClass || tp.decls.isInstanceOf[PackageScope])
} }
protected var verbose = false
def info(msg: => String) = def info(msg: => String) =
if (verbose) println("[reflect-compiler] "+msg) if (settings.verbose.value) println("[reflect-compiler] "+msg)
} }

View File

@ -82,8 +82,10 @@ abstract class SymbolLoaders {
/** /**
* A lazy type that completes itself by calling parameter doComplete. * A lazy type that completes itself by calling parameter doComplete.
* Any linked modules/classes or module classes are also initialized. * Any linked modules/classes or module classes are also initialized.
* Todo: consider factoring out behavior from TopClassCompleter/SymbolLoader into
* supertrait SymLoader
*/ */
abstract class SymbolLoader extends LazyType { abstract class SymbolLoader extends SymLoader {
/** Load source or class file for `root`, return */ /** Load source or class file for `root`, return */
protected def doComplete(root: Symbol): Unit protected def doComplete(root: Symbol): Unit
@ -105,6 +107,7 @@ abstract class SymbolLoaders {
case _ => () case _ => ()
}) })
} }
override def complete(root: Symbol) : Unit = { override def complete(root: Symbol) : Unit = {
def signalError(ex: Exception) { def signalError(ex: Exception) {
ok = false ok = false

View File

@ -437,7 +437,7 @@ abstract class ClassfileParser {
def loadClassSymbol(name: Name) = { def loadClassSymbol(name: Name) = {
val s = name.toString val s = name.toString
val file = global.classPath findSourceFile s getOrElse { val file = global.classPath findSourceFile s getOrElse {
throw new MissingRequirementError("class " + s) MissingRequirementError.notFound("class " + s)
} }
val completer = new global.loaders.ClassfileLoader(file) val completer = new global.loaders.ClassfileLoader(file)
var owner: Symbol = definitions.RootClass var owner: Symbol = definitions.RootClass
@ -673,27 +673,6 @@ abstract class ClassfileParser {
} }
} }
/** Convert array parameters denoting a repeated parameter of a Java method
* to `JavaRepeatedParamClass` types.
*/
private def arrayToRepeated(tp: Type): Type = tp match {
case MethodType(params, rtpe) =>
val formals = tp.paramTypes
assert(formals.last.typeSymbol == definitions.ArrayClass)
val method = params.last.owner
val elemtp = formals.last.typeArgs.head match {
case RefinedType(List(t1, t2), _) if (t1.typeSymbol.isAbstractType && t2.typeSymbol == definitions.ObjectClass) =>
t1 // drop intersection with Object for abstract types in varargs. UnCurry can handle them.
case t =>
t
}
val newParams = method.newSyntheticValueParams(
formals.init :+ appliedType(definitions.JavaRepeatedParamClass.typeConstructor, List(elemtp)))
MethodType(newParams, rtpe)
case PolyType(tparams, rtpe) =>
PolyType(tparams, arrayToRepeated(rtpe))
}
private def sigToType(sym: Symbol, sig: Name): Type = { private def sigToType(sym: Symbol, sig: Name): Type = {
var index = 0 var index = 0
val end = sig.length val end = sig.length

View File

@ -45,7 +45,7 @@ abstract class ICodeReader extends ClassfileParser {
classPath.findSourceFile(name) match { classPath.findSourceFile(name) match {
case Some(classFile) => parse(classFile, cls) case Some(classFile) => parse(classFile, cls)
case _ => throw new MissingRequirementError("Could not find bytecode for " + cls) case _ => MissingRequirementError.notFound("Could not find bytecode for " + cls)
} }
(staticCode, instanceCode) (staticCode, instanceCode)

View File

@ -92,7 +92,7 @@ trait Namers { self: Analyzer =>
updatePosFlags(sym.moduleClass, pos, moduleClassFlags(flags)) updatePosFlags(sym.moduleClass, pos, moduleClassFlags(flags))
var companion: Symbol = NoSymbol var companion: Symbol = NoSymbol
if (sym.owner.isPackageClass && {companion = companionSymbolOf(sym, context); companion != NoSymbol} && if (sym.owner.isPackageClass && {companion = companionSymbolOf(sym, context); companion != NoSymbol} &&
(companion.rawInfo.isInstanceOf[loaders.SymbolLoader] || (companion.rawInfo.isInstanceOf[SymLoader] ||
companion.rawInfo.isComplete && runId(sym.validTo) != currentRunId)) companion.rawInfo.isComplete && runId(sym.validTo) != currentRunId))
// pre-set linked symbol to NoType, in case it is not loaded together with this symbol. // pre-set linked symbol to NoType, in case it is not loaded together with this symbol.
companion.setInfo(NoType) companion.setInfo(NoType)

View File

@ -3880,6 +3880,9 @@ trait Typers extends Modes with Adaptations {
else if (settings.exposeEmptyPackage.value && checkEmptyPackage()) else if (settings.exposeEmptyPackage.value && checkEmptyPackage())
log("Allowing empty package member " + name + " due to settings.") log("Allowing empty package member " + name + " due to settings.")
else { else {
val lastTry = missingHook(RootClass, name)
if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt)
if (settings.debug.value) { if (settings.debug.value) {
log(context.imports)//debug log(context.imports)//debug
} }