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