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:
parent
0a74d04a58
commit
daaa644d6b
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 = "<?>"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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) =>
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue