More changes to get Reflect compiler working.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@25583 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
odersky 2011-08-29 12:45:19 +00:00
parent 6043a4a7ed
commit 92a40f1e57
17 changed files with 192 additions and 108 deletions

View File

@ -659,39 +659,26 @@ trait Definitions extends reflect.api.StandardDefinitions {
}
def packageExists(packageName: String): Boolean =
getModuleIfDefined(packageName).isPackage
private def getModuleOrClass(path: Name, len: Int): Symbol = {
val point = path lastPos('.', len - 1)
val owner = if (point > 0) getModuleOrClass(path.toTermName, point) else RootClass
val name = path subName (point + 1, len)
val sym = owner.info member name
val result = if (path.isTermName) sym.suchThat(_ hasFlag MODULE) else sym
if (result != NoSymbol) result
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)
}
}
}
/** If you're looking for a class, pass a type name.
* If a module, a term name.
*/
private def getModuleOrClass(path: Name): Symbol = {
val module = path.isTermName
val fullname = path.toTermName
if (fullname == nme.NO_NAME)
return NoSymbol
var sym: Symbol = RootClass
var i = 0
var j = fullname.pos('.', i)
while (j < fullname.length) {
// val sym0 = sym //DEBUG
sym = sym.info.member(fullname.subName(i, j))
// if (sym == NoSymbol)
// println("no member "+fullname.subName(i, j)+" found in "+sym0+sym0.info.getClass+" "+sym0.info.typeSymbol.info.getClass)
i = j + 1
j = fullname.pos('.', i)
}
val result =
if (module) sym.info.member(fullname.subName(i, j)).suchThat(_ hasFlag MODULE)
else sym.info.member(fullname.subName(i, j).toTypeName)
if (result == NoSymbol) {
// println("no member "+fullname.subName(i, j)+" found in "+sym+" "+module)
if (settings.debug.value)
{ log(sym.info); log(sym.info.members) }//debug
throw new MissingRequirementError((if (module) "object " else "class ") + fullname)
}
result
}
private def getModuleOrClass(path: Name): Symbol = getModuleOrClass(path, path.length)
private def newClass(owner: Symbol, name: TypeName, parents: List[Type]): Symbol = {
val clazz = owner.newClass(NoPosition, name)
@ -840,7 +827,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
def init() {
if (isInitialized) return
EmptyPackageClass setInfo ClassInfoType(Nil, new Scope, EmptyPackageClass)
EmptyPackageClass setInfo ClassInfoType(Nil, newPackageScope(EmptyPackageClass), EmptyPackageClass)
EmptyPackage setInfo EmptyPackageClass.tpe
RootClass.info.decls enter EmptyPackage
@ -937,5 +924,5 @@ trait Definitions extends reflect.api.StandardDefinitions {
assert(Delegate_scalaCallers contains scalaCaller)
Delegate_scalaCallerTargets += (scalaCaller -> methSym)
}
}
}
}

View File

@ -3,4 +3,4 @@
* @author Martin Odersky
*/
package scala.reflect.internal
case class FatalError(msg: String) extends Throwable(msg)
case class FatalError(msg: String) extends Exception(msg)

View File

@ -316,7 +316,7 @@ trait Names extends api.Names {
def lastIndexOf(ch: Char) = toChars lastIndexOf ch
/** Return the subname with characters from start to end-1. */
/** Return the subname with characters from from to to-1. */
def subName(from: Int, to: Int): Name
/** Replace all occurrences of `from` by `to` in

View File

@ -74,13 +74,10 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
}
/** Returns a new scope with the same content as this one. */
def cloneScope: Scope = {
val clone = new Scope()
this.toList foreach (clone enter _)
clone
}
def mkScope: Scope = new Scope()
def cloneScope: Scope = mkScope(this.toList)
/** Returns a new scope of the same class as this one, with initial elements `decls` */
def mkScope(decls: List[Symbol] = Nil): Scope = new Scope(decls)
/** is the scope empty? */
override def isEmpty: Boolean = elems eq null
@ -302,7 +299,7 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
override def foreach[U](p: Symbol => U): Unit = toList foreach p
override def filter(p: Symbol => Boolean): Scope =
if (!(toList forall p)) new Scope(toList filter p) else this
if (!(toList forall p)) mkScope(toList filter p) else this
override def mkString(start: String, sep: String, end: String) =
toList.map(_.defString).mkString(start, sep, end)
@ -311,7 +308,11 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
}
/** Create a new scope */
def newScope: Scope = new Scope
/** Create new scope for the members of package `pkg` */
def newPackageScope(pkgClass: Symbol): Scope = new Scope
def newScopeWith(elems: Symbol*) = {
val scope = newScope

View File

@ -41,6 +41,12 @@ abstract class SymbolTable extends api.Universe
/** Are we compiling for .NET? */
def forMSIL: Boolean = false
/** A last effort if symbol in a select <owner>.<name> is not found.
* This is overridden by the reflection compiler to make up a package
* when it makes sense (i.e. <owner> is a package and <name> is a term name).
*/
def missingHook(owner: Symbol, name: Name): Symbol = NoSymbol
/** A period is an ordinal number for a phase in a run.
* Phases in later runs have higher periods than phases in earlier runs.
* Later phases have higher periods than earlier phases in the same run.

View File

@ -1508,6 +1508,9 @@ trait Types extends api.Types { self: SymbolTable =>
def apply(parents: List[Type], decls: Scope, clazz: Symbol): RefinedType =
new RefinedType0(parents, decls, clazz)
}
/** Overridden in reflection compiler */
def validateClassInfo(tp: ClassInfoType) {}
/** A class representing a class info
*/
@ -1516,6 +1519,7 @@ trait Types extends api.Types { self: SymbolTable =>
override val decls: Scope,
override val typeSymbol: Symbol) extends CompoundType
{
validateClassInfo(this)
/** refs indices */
private final val NonExpansive = 0
@ -3405,7 +3409,7 @@ A type's typeSymbol should never be inspected directly.
val elems = scope.toList
val elems1 = mapOver(elems)
if (elems1 eq elems) scope
else new Scope(elems1)
else scope.mkScope(elems1)
}
/** Map this function over given list of symbols */
@ -5499,11 +5503,16 @@ A type's typeSymbol should never be inspected directly.
private val lubResults = new mutable.HashMap[(Int, List[Type]), Type]
private val glbResults = new mutable.HashMap[(Int, List[Type]), Type]
def lub(ts: List[Type]): Type = try {
lub(ts, lubDepth(ts))
} finally {
lubResults.clear()
glbResults.clear()
def lub(ts: List[Type]): Type = ts match {
case List() => NothingClass.tpe
case List(t) => t
case _ =>
try {
lub(ts, lubDepth(ts))
} finally {
lubResults.clear()
glbResults.clear()
}
}
/** The least upper bound wrt <:< of a list of types */
@ -5631,26 +5640,39 @@ A type's typeSymbol should never be inspected directly.
private var globalGlbDepth = 0
private final val globalGlbLimit = 2
def glb(ts: List[Type]): Type = try {
glb(ts, lubDepth(ts))
} finally {
lubResults.clear()
glbResults.clear()
/** The greatest lower bound wrt <:< of a list of types */
def glb(ts: List[Type]): Type = elimSuper(ts) match {
case List() => AnyClass.tpe
case List(t) => t
case ts0 =>
try {
glbNorm(ts0, lubDepth(ts0))
} finally {
lubResults.clear()
glbResults.clear()
}
}
private def glb(ts: List[Type], depth: Int): Type = elimSuper(ts) match {
case List() => AnyClass.tpe
case List(t) => t
case ts0 => glbNorm(ts0, depth)
}
/** The greatest lower bound wrt <:< of a list of types */
private def glb(ts: List[Type], depth: Int): Type = {
def glb0(ts0: List[Type]): Type = elimSuper(ts0) match {
/** The greatest lower bound wrt <:< of a list of types, which have been normalized
* wrt elimSuper */
private def glbNorm(ts: List[Type], depth: Int): Type = {
def glb0(ts0: List[Type]): Type = ts0 match {
case List() => AnyClass.tpe
case List(t) => t
case ts @ PolyType(tparams, _) :: _ =>
val tparams1 = (tparams, matchingBounds(ts, tparams).transpose).zipped map
((tparam, bounds) => tparam.cloneSymbol.setInfo(lub(bounds, depth)))
PolyType(tparams1, glb0(matchingInstTypes(ts, tparams1)))
PolyType(tparams1, glbNorm(matchingInstTypes(ts, tparams1), depth))
case ts @ MethodType(params, _) :: rest =>
MethodType(params, glb0(matchingRestypes(ts, params map (_.tpe))))
MethodType(params, glbNorm(matchingRestypes(ts, params map (_.tpe)), depth))
case ts @ NullaryMethodType(_) :: rest =>
NullaryMethodType(glb0(matchingRestypes(ts, Nil)))
NullaryMethodType(glbNorm(matchingRestypes(ts, Nil), depth))
case ts @ TypeBounds(_, _) :: rest =>
TypeBounds(lub(ts map (_.bounds.lo), depth), glb(ts map (_.bounds.hi), depth))
case ts =>

View File

@ -36,7 +36,9 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ {
try {
new Scan(bytes, offset, classRoot, moduleRoot, filename).run()
} catch {
case ex: IOException =>
case ex: IOException =>
throw ex
case ex: MissingRequirementError =>
throw ex
case ex: Throwable =>
/*if (settings.debug.value)*/ ex.printStackTrace()
@ -815,14 +817,12 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ {
protected def errorBadSignature(msg: String) =
throw new RuntimeException("malformed Scala signature of " + classRoot.name + " at " + readIndex + "; " + msg)
protected def errorMissingRequirement(msg: String): Nothing =
if (debug) errorBadSignature(msg)
else throw new IOException("class file needed by "+classRoot.name+" is missing.\n"+msg)
protected def errorMissingRequirement(name: Name, owner: Symbol): Nothing =
errorMissingRequirement(
"reference " + (if (name.isTypeName) "type " else "value ") +
name.decode + " of " + owner.tpe.widen + " refers to nonexisting symbol.")
protected def errorMissingRequirement(name: Name, owner: Symbol): Symbol =
missingHook(owner, name) orElse {
throw new MissingRequirementError(
"reference " + (if (name.isTypeName) "type " else "value ") +
name.decode + " of " + owner.tpe.widen)
}
def inferMethodAlternative(fun: Tree, argtpes: List[Type], restpe: Type) {} // can't do it; need a compiler for that.

View File

@ -16,6 +16,7 @@ import java.lang.reflect.{
WildcardType,
AnnotatedElement
}
import internal.MissingRequirementError
import internal.pickling.ByteCodecs
import internal.ClassfileConstants._
import internal.pickling.UnPickler
@ -41,6 +42,14 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
*/
def unpickleClass(clazz: Symbol, module: Symbol, jclazz: jClass[_]): Unit = {
def markAbsent(tpe: Type) = List(clazz, module, module.moduleClass) foreach (_ setInfo tpe)
def handleError(ex: Exception) = {
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)
}
try {
println("unpickling " + clazz + " " + module) //debug
markAbsent(NoType)
@ -69,13 +78,10 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
}
}
} catch {
case ex: MissingRequirementError =>
handleError(ex)
case ex: IOException =>
markAbsent(ErrorType)
if (settings.debug.value) ex.printStackTrace()
val msg = ex.getMessage()
throw new IOException(
if (msg eq null) "reflection error while loading " + clazz.name
else "error while loading " + clazz.name + ", " + msg)
handleError(ex)
}
}
@ -133,9 +139,14 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
val tparams = jclazz.getTypeParameters.toList map createTypeParameter
val jsuperclazz = jclazz.getGenericSuperclass
val superclazz = if (jsuperclazz == null) AnyClass.tpe else typeToScala(jsuperclazz)
val parents = superclazz :: (jclazz.getGenericInterfaces.toList map typeToScala)
val parents = try {
parentsLevel += 1
val jsuperclazz = jclazz.getGenericSuperclass
val superclazz = if (jsuperclazz == null) AnyClass.tpe else typeToScala(jsuperclazz)
superclazz :: (jclazz.getGenericInterfaces.toList map typeToScala)
} finally {
parentsLevel -= 1
}
clazz setInfo polyType(tparams, new ClassInfoType(parents, newScope, clazz))
module.moduleClass setInfo new ClassInfoType(List(), newScope, module.moduleClass)
module setInfo module.moduleClass.tpe
@ -143,16 +154,32 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
def enter(sym: Symbol) =
(if (sym.isStatic) module.moduleClass else clazz).info.decls enter sym
for (jfield <- jclazz.getDeclaredFields)
enter(jfieldAsScala(jfield))
pendingLoadActions = { () =>
for (jmeth <- jclazz.getDeclaredMethods)
enter(jmethodAsScala(jmeth))
for (jfield <- jclazz.getDeclaredFields)
enter(jfieldAsScala(jfield))
for (jconstr <- jclazz.getConstructors)
enter(jconstrAsScala(jconstr))
for (jmeth <- jclazz.getDeclaredMethods)
enter(jmethodAsScala(jmeth))
for (jconstr <- jclazz.getConstructors)
enter(jconstrAsScala(jconstr))
} :: pendingLoadActions
if (parentsLevel == 0) {
while (!pendingLoadActions.isEmpty) {
val item = pendingLoadActions.head
pendingLoadActions = pendingLoadActions.tail
item()
}
}
}
}
/** used to avoid cyclies */
var parentsLevel = 0
var pendingLoadActions: List[() => Unit] = Nil
/**
* If Java modifiers `mods` contain STATIC, return the module class
@ -252,13 +279,20 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
* The Scala package with given fully qualified name. Unlike `packageNameToScala`,
* this one bypasses the cache.
*/
private def makeScalaPackage(fullname: String): Symbol = {
def makeScalaPackage(fullname: String): Symbol = {
println("make scala pkg "+fullname)
val split = fullname lastIndexOf '.'
val owner = if (split > 0) packageNameToScala(fullname take split) else RootClass
assert(owner.isModuleClass, owner+" when making "+fullname)
val name = fullname drop (split + 1)
val pkg = owner.info decl newTermName(name)
val name = newTermName(fullname drop (split + 1))
var pkg = owner.info decl name
if (pkg == NoSymbol) {
pkg = owner.newPackage(NoPosition, name)
pkg.moduleClass setInfo newPackageType(pkg.moduleClass)
pkg setInfo typeRef(pkg.owner.thisType, pkg.moduleClass, Nil)
owner.info.decls enter pkg
} else if (!pkg.isPackage)
throw new ReflectError(pkg+" is not a package")
println(" = "+pkg+"/"+pkg.moduleClass)
pkg.moduleClass
}
@ -329,7 +363,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
val tparam = owner.newExistential(NoPosition, newTypeName("T$" + tparams.length))
.setInfo(TypeBounds(
lub(jwild.getLowerBounds.toList map typeToScala),
glb(scala.tools.nsc.util.trace("glb args")(jwild.getUpperBounds.toList) map typeToScala map objToAny)))
glb(scala.tools.nsc.util.trace("glb args of "+owner)(jwild.getUpperBounds.toList) map typeToScala map objToAny)))
tparams += tparam
typeRef(NoPrefix, tparam, List())
case _ =>
@ -428,4 +462,6 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable =>
copyAnnotations(meth, jconstr)
meth
}
}
}
class ReflectError(msg: String) extends java.lang.Error(msg)

View File

@ -22,6 +22,7 @@ trait Loaders { self: SymbolTable =>
*/
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
@ -80,7 +81,7 @@ trait Loaders { self: SymbolTable =>
* a TopClassCompleter type. When any of the two symbols is forced via info,
* the TopClassCompleter will sort things out.
*/
def newPackageType(pkg: Symbol) = new ClassInfoType(List(), new PackageScope(pkg), pkg) {
def newPackageType(pkgClass: Symbol) = new ClassInfoType(List(), new PackageScope(pkgClass), pkgClass) {
/*
override def decl(name: Name): Symbol =
(decls lookup name) orElse {
@ -94,24 +95,31 @@ trait Loaders { self: SymbolTable =>
override def findMember(name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean) =
member(name).filter (m => m.hasAllFlags(requiredFlags) && !m.hasFlag(excludedFlags))
*/
override def safeToString = pkg.toString
override def safeToString = pkgClass.toString
}
class PackageScope(pkg: Symbol) extends Scope {
class PackageScope(pkgClass: Symbol) extends Scope {
override def lookupEntry(name: Name): ScopeEntry = {
val e = super.lookupEntry(name)
if (e != null)
e
else try {
if (name.isTypeName) jClass.forName(pkg.fullName + "." + name)
val (clazz, module) = createClassModule(pkg, name.toTypeName, new TopClassCompleter(_, _))
println("created "+module+"/"+module.moduleClass+" in "+pkg+", scope = "+(this map (_.name)))
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)))
lookupEntry(name)
} catch {
case ex: ClassNotFoundException =>
println("not found: "+pkg.fullName + "." + name)
println("not found : "+pkgClass.fullName + "." + name)
null
}
}
override def mkScope(decls: List[Symbol]) = {
val result = new PackageScope(pkgClass)
decls foreach (result enter)
result
}
}
override def newPackageScope(pkgClass: Symbol) = new PackageScope(pkgClass)
}

View File

@ -72,6 +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)
@ -80,4 +81,3 @@ object Test extends Mirror with App {
val ms = sym.info.members.toList map (_.initialize)
println("members = "+(ms map (_.defString) mkString ("\n ")))
}
*/

View File

@ -6,4 +6,21 @@ package runtime
* It can be used either from the reflexive mirror itself (class Universe), or else from
* a runtime compiler that uses reflection to get a class information (class scala.tools.nsc.ReflectGlobal)
*/
trait SymbolTable extends internal.SymbolTable with JavaToScala with ScalaToJava with Loaders
trait SymbolTable extends internal.SymbolTable with JavaToScala with ScalaToJava with Loaders {
/** If `owner` is a package class and `name` is a term name, make a new package
* <owner>.<name>, otherwise return NoSymbol
*/
override def missingHook(owner: Symbol, name: Name): Symbol =
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)
super.missingHook(owner, name)
}
/** Assert that packages have package scopes */
override def validateClassInfo(tp: ClassInfoType) {
assert(!tp.typeSymbol.isPackageClass || tp.decls.isInstanceOf[PackageScope])
}
}

View File

@ -5,7 +5,6 @@
package scala.tools.nsc
import java.io.IOException
import scala.collection.mutable.ListBuffer
import io.File

View File

@ -5,7 +5,6 @@
package scala.tools.nsc
import java.io.IOException
import java.net.URL
import scala.tools.util.PathResolver

View File

@ -13,6 +13,7 @@ import scala.compat.Platform.currentTime
import scala.tools.nsc.util.{ ClassPath }
import classfile.ClassfileParser
import reflect.internal.Flags._
import reflect.internal.MissingRequirementError
import util.Statistics._
import scala.tools.nsc.io.AbstractFile
@ -105,6 +106,14 @@ abstract class SymbolLoaders {
})
}
override def complete(root: Symbol) : Unit = {
def signalError(ex: Exception) {
ok = false
if (settings.debug.value) ex.printStackTrace()
val msg = ex.getMessage()
globalError(
if (msg eq null) "i/o error while loading " + root.name
else "error while loading " + root.name + ", " + msg);
}
try {
val start = currentTime
val currentphase = phase
@ -116,12 +125,9 @@ abstract class SymbolLoaders {
setSource(root.companionSymbol) // module -> class, class -> module
} catch {
case ex: IOException =>
ok = false
if (settings.debug.value) ex.printStackTrace()
val msg = ex.getMessage()
globalError(
if (msg eq null) "i/o error while loading " + root.name
else "error while loading " + root.name + ", " + msg);
signalError(ex)
case ex: MissingRequirementError =>
signalError(ex)
}
initRoot(root)
if (!root.isPackageClass) initRoot(root.companionSymbol)

View File

@ -64,7 +64,7 @@ abstract class Flatten extends InfoTransform {
typeRef(sym.toplevelClass.owner.thisType, sym, Nil)
case ClassInfoType(parents, decls, clazz) =>
var parents1 = parents
val decls1 = new Scope
val decls1 = decls.mkScope()
if (clazz.isPackageClass) {
atPhase(phase.next)(decls foreach (decls1 enter _))
}

View File

@ -3668,9 +3668,12 @@ trait Typers extends Modes with Adaptations {
if (name == nme.ERROR && forInteractive)
return makeErrorTree
if (!qual.tpe.widen.isErroneous)
if (!qual.tpe.widen.isErroneous) {
val lastTry = missingHook(qual.tpe.typeSymbol, name)
if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt)
notAMemberError(tree.pos, qual, name)
}
if (forInteractive) makeErrorTree else setError(tree)
} else {
val tree1 = tree match {

View File

@ -7,7 +7,7 @@ package scala.tools
package nsc
package util
import java.io.{File, FileInputStream, PrintStream, IOException}
import java.io.{File, FileInputStream, PrintStream}
import java.lang.Long.toHexString
import java.lang.Float.intBitsToFloat
import java.lang.Double.longBitsToDouble