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 {
if (settings.debug.value) { log(sym.info); log(sym.info.members) }//debug
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 a module, a term name.
*/

View File

@ -6,12 +6,18 @@
package scala.reflect
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 {
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 {
case x: MissingRequirementError => Some(x.req)
case _ => None
case x: MissingRequirementError => x.req
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. */
def openPackageModule(pkgClass: Symbol) {
val pkgModule = pkgClass.info.decl(nme.PACKAGEkw)
def fromSource = pkgModule.rawInfo match {
case ltp: LazyType => ltp.fromSource
case ltp: SymLoader => ltp.fromSource
case _ => false
}
if (pkgModule.isModule && !fromSource) {

View File

@ -1817,7 +1817,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
override def toString = compose(
kindString,
if (hasMeaninglessName) owner.nameString else nameString
if (hasMeaninglessName) owner.decodedName + idString else nameString
)
/** 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
*/
abstract case class ThisType(sym: Symbol) extends SingletonType {
assert(sym.isClass)
//assert(sym.isClass && !sym.isModuleClass || sym.isRoot, sym)
override def isTrivial: Boolean = sym.isPackageClass
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.
*/
abstract class LazyType extends Type {
def fromSource = false
override def isComplete: Boolean = false
override def complete(sym: Symbol)
override def safeToString = "<?>"

View File

@ -195,12 +195,12 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ {
val name = readNameRef()
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 {
case nme.ROOT => definitions.RootClass
case nme.ROOTPKG => definitions.RootPackage
case _ =>
val s = owner.info.decl(name)
if (tag == EXTref) s else s.moduleClass
case _ => adjust(owner.info.decl(name))
}
def nestedObjectSymbol: Symbol = {
// 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.
nestedObjectSymbol orElse {
// (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 =
missingHook(owner, name) orElse {
throw new MissingRequirementError(
MissingRequirementError.notFound(
"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.

View File

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

View File

@ -20,7 +20,7 @@ trait Loaders { self: SymbolTable =>
* by unpickling information from the corresponding Java class. If no Java class
* 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() {
// println("wrong guess; making package "+clazz)
// 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 {
assert(pkgClass.isType)
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)
else if (invalidClassName(name) || (negatives contains name))
null
else try {
jClass.forName(pkgClass.fullName + "." + name)
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)
} catch {
case (_: ClassNotFoundException) | (_: NoClassDefFoundError) =>

View File

@ -23,9 +23,7 @@ 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)
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.
* 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 */
protected def doComplete(root: Symbol): Unit
@ -105,6 +107,7 @@ abstract class SymbolLoaders {
case _ => ()
})
}
override def complete(root: Symbol) : Unit = {
def signalError(ex: Exception) {
ok = false

View File

@ -437,7 +437,7 @@ abstract class ClassfileParser {
def loadClassSymbol(name: Name) = {
val s = name.toString
val file = global.classPath findSourceFile s getOrElse {
throw new MissingRequirementError("class " + s)
MissingRequirementError.notFound("class " + s)
}
val completer = new global.loaders.ClassfileLoader(file)
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 = {
var index = 0
val end = sig.length

View File

@ -45,7 +45,7 @@ abstract class ICodeReader extends ClassfileParser {
classPath.findSourceFile(name) match {
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)

View File

@ -92,7 +92,7 @@ trait Namers { self: Analyzer =>
updatePosFlags(sym.moduleClass, pos, moduleClassFlags(flags))
var companion: Symbol = 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))
// pre-set linked symbol to NoType, in case it is not loaded together with this symbol.
companion.setInfo(NoType)

View File

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