Skip to content
Permalink
Browse files

tests and fixes for the mirror API

  • Loading branch information
xeno-by committed Jun 8, 2012
1 parent 2123201 commit abc1c0be79ac2fb2b0e75c87a489570a9c71aa6e
Showing with 471 additions and 108 deletions.
  1. +36 −41 src/reflect/scala/reflect/api/Mirrors.scala
  2. +1 −1 src/reflect/scala/reflect/api/TagInterop.scala
  3. +62 −33 src/reflect/scala/reflect/runtime/JavaMirrors.scala
  4. +1 −1 test/files/run/reflect-overload.scala
  5. +2 −0 test/files/run/reflection-constructormirror-inner-badpath.check
  6. +32 −0 test/files/run/reflection-constructormirror-inner-badpath.scala
  7. +1 −0 test/files/run/reflection-constructormirror-inner-good.check
  8. +26 −0 test/files/run/reflection-constructormirror-inner-good.scala
  9. +2 −0 test/files/run/reflection-constructormirror-nested-badpath.check
  10. +32 −0 test/files/run/reflection-constructormirror-nested-badpath.scala
  11. +1 −0 test/files/run/reflection-constructormirror-nested-good.check
  12. +26 −0 test/files/run/reflection-constructormirror-nested-good.scala
  13. +2 −0 test/files/run/reflection-constructormirror-toplevel-badpath.check
  14. +33 −0 test/files/run/reflection-constructormirror-toplevel-badpath.scala
  15. +1 −0 test/files/run/reflection-constructormirror-toplevel-good.check
  16. +27 −0 test/files/run/reflection-constructormirror-toplevel-good.scala
  17. +1 −1 test/files/run/reflection-fieldmirror-ctorparam.scala
  18. +1 −1 test/files/run/reflection-fieldmirror-getsetval.scala
  19. +1 −1 test/files/run/reflection-fieldmirror-getsetvar.scala
  20. +2 −2 test/files/run/reflection-fieldmirror-nmelocalsuffixstring.scala
  21. +2 −2 test/files/run/reflection-fieldmirror-privatethis.scala
  22. +1 −1 test/files/run/reflection-fieldmirror-sanitycheck.scala
  23. +3 −3 test/files/run/reflection-implClass.scala
  24. +2 −0 test/files/run/reflection-modulemirror-inner-badpath.check
  25. +24 −0 test/files/run/reflection-modulemirror-inner-badpath.scala
  26. +2 −0 test/files/run/reflection-modulemirror-inner-good.check
  27. +23 −0 test/files/run/reflection-modulemirror-inner-good.scala
  28. +2 −0 test/files/run/reflection-modulemirror-nested-badpath.check
  29. +26 −0 test/files/run/reflection-modulemirror-nested-badpath.scala
  30. +2 −0 test/files/run/reflection-modulemirror-nested-good.check
  31. +24 −0 test/files/run/reflection-modulemirror-nested-good.scala
  32. +2 −0 test/files/run/reflection-modulemirror-toplevel-badpath.check
  33. +26 −0 test/files/run/reflection-modulemirror-toplevel-badpath.scala
  34. +1 −0 test/files/run/reflection-modulemirror-toplevel-good.check
  35. +20 −0 test/files/run/reflection-modulemirror-toplevel-good.scala
  36. +1 −1 test/files/run/reflection-simple.scala
  37. +1 −1 test/files/run/t5256a.scala
  38. +1 −1 test/files/run/t5256b.scala
  39. +1 −1 test/files/run/t5256c.scala
  40. +1 −1 test/files/run/t5256d.check
  41. +1 −1 test/files/run/t5256d.scala
  42. +3 −3 test/files/run/t5256e.check
  43. +1 −1 test/files/run/t5256e.scala
  44. +6 −6 test/files/run/t5256f.check
  45. +2 −2 test/files/run/t5256f.scala
  46. +1 −1 test/files/run/t5256g.scala
  47. +1 −1 test/files/run/t5256h.scala
  48. +1 −1 test/files/run/t5423.scala
@@ -5,10 +5,6 @@ trait Mirrors { self: Universe =>

type RuntimeClass >: Null

// [Eugene++ to Martin] how do we reflect against inner classes?
// presumably, we should add `reflectClass` to both InstanceMirror (inner classes) and TemplateMirror (nested classes)
// in the former case, the resulting ClassMirror should remember the outer instance that spawned it to use it in reflective construction

// [Eugene] also, it might make sense to provide shortcuts for the API
//
// for example, right now to invoke the same method for several different instances, you need:
@@ -31,8 +27,8 @@ trait Mirrors { self: Universe =>
/** The instance value reflected by this mirror */
def instance: Any

/** The mirror corresponding to the run-time class of the reflected instance. */
def reflectClass: ClassMirror
/** The symbol corresponding to the run-time class of the reflected instance. */
def symbol: ClassSymbol

/** Get value of field in reflected instance.
* @field A field symbol that should represent a field of the instance class.
@@ -48,6 +44,12 @@ trait Mirrors { self: Universe =>
* @throws ???
*/
def reflectMethod(method: MethodSymbol): MethodMirror

/** .. */
def reflectClass(cls: ClassSymbol): ClassMirror

/** .. */
def reflectModule(mod: ModuleSymbol): ModuleMirror
}

/** A mirror that reflects a field */
@@ -57,7 +59,7 @@ trait Mirrors { self: Universe =>
def receiver: AnyRef

/** The field symbol representing the field */
def field: TermSymbol
def symbol: TermSymbol

/** Retrieves the value stored in the field */
def get: Any
@@ -73,9 +75,10 @@ trait Mirrors { self: Universe =>
def receiver: AnyRef

/** The method symbol representing the method */
def method: MethodSymbol
def symbol: MethodSymbol

/** The result of applying the method to the given arguments */
// [Eugene+++] If it's a constructor, it should account for inner classes
def apply(args: Any*): Any
}

@@ -97,8 +100,6 @@ trait Mirrors { self: Universe =>
/** The Scala symbol corresponding to the reflected runtime class or module. */
def symbol: Symbol

// [Eugene++ to Martin] I've removed `typeSignature`, because we can obtain it via `symbol.typeSignature`

/** Optionally, the mirror of the companion reflected by this mirror.
* If this mirror reflects a Scala object, the mirror for the companion class, or None
* if the mirror represents a Scala object that comes without a class.
@@ -157,46 +158,24 @@ trait Mirrors { self: Universe =>
def companion: Option[ModuleMirror]
}

/** The API of a mirror for a reflective universe */
trait RuntimeMirror extends MirrorOf[Mirrors.this.type] { self =>
/** A mirror that reflects instances and static classes */
trait ReflectiveMirror extends MirrorOf[Mirrors.this.type] {

/** A reflective mirror for the given object
* @param obj An arbitrary value
* @return The mirror for `obj`.
*/
def reflect(obj: Any): InstanceMirror

/** A reflective mirror for the given Runtime class
* @param runtimeClass A Runtime class object
* @return The mirror for `runtimeClass`
*/
def reflectClass(runtimeClass: RuntimeClass): ClassMirror

/** A reflective mirror for the Runtime class with the given name in the
* current classloader.
* @param name The fully qualified name of the class
* @return The mirror for the runtime class with fully qualified name
* `name` in the current class loader.
* @throws java.lang.ClassNotFoundException if no class with that name exists
* to do: throws anything else?
*/
def reflectClass(fullName: String): ClassMirror
/** .. */
def reflectClass(cls: ClassSymbol): ClassMirror

/** A reflective mirror for the given Runtime class
* @param runtimeClass A Runtime class object
* @return The mirror for `runtimeClass`
*/
def reflectModule(runtimeClass: RuntimeClass): ModuleMirror
/** .. */
def reflectModule(mod: ModuleSymbol): ModuleMirror
}

/** A reflective mirror for the Runtime class with the given name in the
* current classloader.
* @param name The fully qualified name of the class
* @return The mirror for the runtime class with fully qualified name
* `name` in the current class loader.
* @throws java.lang.ClassNotFoundException if no class with that name exists
* to do: throws anything else?
*/
def reflectModule(fullName: String): ModuleMirror
/** The API of a mirror for a reflective universe */
trait RuntimeMirror extends ReflectiveMirror { self =>

/** Maps a Scala type to the corresponding Java class object
*/
@@ -209,5 +188,21 @@ trait Mirrors { self: Universe =>
* because there is no unique Java class corresponding to a Scala generic array
*/
def runtimeClass(cls: ClassSymbol): RuntimeClass

/** A class symbol for the specified runtime class.
* @return The class symbol for the runtime class in the current class loader.
* @throws java.lang.ClassNotFoundException if no class with that name exists
* @throws scala.reflect.internal.MissingRequirementError if no corresponding symbol exists
* to do: throws anything else?
*/
def classSymbol(rtcls: RuntimeClass): ClassSymbol

/** A module symbol for the specified runtime class.
* @return The module symbol for the runtime class in the current class loader.
* @throws java.lang.ClassNotFoundException if no class with that name exists
* @throws scala.reflect.internal.MissingRequirementError if no corresponding symbol exists
* to do: throws anything else?
*/
def moduleSymbol(rtcls: RuntimeClass): ModuleSymbol
}
}
@@ -25,7 +25,7 @@ trait TagInterop { self: JavaUniverse =>
mirror.universe match {
case ju: JavaUniverse =>
val jm = mirror.asInstanceOf[ju.Mirror]
val sym = jm.reflectClass(manifest.erasure).symbol
val sym = jm.classSymbol(manifest.erasure)
val tpe =
if (manifest.typeArguments.isEmpty) sym.asType
else ju.appliedType(sym.asTypeConstructor, manifest.typeArguments map (targ => ju.manifestToTypeTag(jm, targ)) map (_.in(jm).tpe))
@@ -32,6 +32,8 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym
jm
}

override type RuntimeClass = java.lang.Class[_]

override type Mirror = JavaMirror

override lazy val rootMirror: Mirror = createMirror(NoSymbol, rootClassLoader)
@@ -105,30 +107,32 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym

// ----------- Implementations of mirror operations and classes -------------------

def reflect(obj: Any): InstanceMirror =
new JavaInstanceMirror(obj.asInstanceOf[AnyRef])

def reflectClass(runtimeClass: RuntimeClass): ClassMirror =
new JavaClassMirror(classToScala(runtimeClass))

def reflectClass(fullName: String): ClassMirror =
reflectClass(java.lang.Class.forName(fullName))
def reflect(obj: Any): InstanceMirror = new JavaInstanceMirror(obj.asInstanceOf[AnyRef])

def reflectModule(runtimeClass: RuntimeClass): ModuleMirror =
new JavaModuleMirror(classToScala(runtimeClass).companionModule.asModuleSymbol)
def reflectClass(cls: ClassSymbol): ClassMirror = {
if (!cls.isStatic) throw new Error("this is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror")
new JavaClassMirror(null, cls)
}

def reflectModule(fullName: String): ModuleMirror =
reflectModule(java.lang.Class.forName(fullName))
def reflectModule(mod: ModuleSymbol): ModuleMirror = {
if (!mod.isStatic) throw new Error("this is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror")
new JavaModuleMirror(null, mod)
}

def runtimeClass(tpe: Type): RuntimeClass = typeToJavaClass(tpe)

def runtimeClass(cls: ClassSymbol): RuntimeClass = classToJava(cls)

def classSymbol(rtcls: RuntimeClass): ClassSymbol = classToScala(rtcls)

def moduleSymbol(rtcls: RuntimeClass): ModuleSymbol = classToScala(rtcls).companionModule.asModuleSymbol

private class JavaInstanceMirror(obj: AnyRef)
extends InstanceMirror {
def instance = obj
def reflectClass = wholemirror.reflectClass(obj.getClass)
def symbol = wholemirror.classSymbol(obj.getClass)
def reflectField(field: TermSymbol): FieldMirror = {
// [Eugene+++] check whether `field` represents a member of a `symbol`
if (field.isMethod || field.isModule) throw new Error(s"""
|expected a field symbol, you provided a ${field.kind} symbol
|A typical cause of this problem is using a field accessor symbol instead of a field symbol.
@@ -139,79 +143,101 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym
""".trim.stripMargin)
new JavaFieldMirror(obj, field)
}
def reflectMethod(method: MethodSymbol): MethodMirror = new JavaMethodMirror(obj, method)
def reflectMethod(method: MethodSymbol): MethodMirror = {
// [Eugene+++] check whether `method` represents a member of a `symbol`
new JavaMethodMirror(obj, method)
}
def reflectClass(cls: ClassSymbol): ClassMirror = {
// [Eugene+++] check whether `cls` represents a member of a `symbol`
if (cls.isStatic) throw new Error("this is a static class, use reflectClass on a RuntimeMirror to obtain its ClassMirror")
new JavaClassMirror(instance, cls)
}
def reflectModule(mod: ModuleSymbol): ModuleMirror = {
// [Eugene+++] check whether `mod` represents a member of a `symbol`
if (mod.isStatic) throw new Error("this is a static module, use reflectModule on a RuntimeMirror to obtain its ModuleMirror")
new JavaModuleMirror(instance, mod)
}
}

private class JavaFieldMirror(val receiver: AnyRef, val field: TermSymbol)
private class JavaFieldMirror(val receiver: AnyRef, val symbol: TermSymbol)
extends FieldMirror {
lazy val jfield = {
val jfield = fieldToJava(field)
val jfield = fieldToJava(symbol)
if (!jfield.isAccessible) jfield.setAccessible(true)
jfield
}
def get = jfield.get(receiver)
def set(value: Any) = {
if (!field.isMutable) throw new Error("cannot set an immutable field")
if (!symbol.isMutable) throw new Error("cannot set an immutable field")
jfield.set(receiver, value)
}
}

private class JavaMethodMirror(val receiver: AnyRef, val method: MethodSymbol)
private class JavaMethodMirror(val receiver: AnyRef, val symbol: MethodSymbol)
extends MethodMirror {
lazy val jmeth = {
val jmeth = methodToJava(method)
val jmeth = methodToJava(symbol)
if (!jmeth.isAccessible) jmeth.setAccessible(true)
jmeth
}
def apply(args: Any*): Any =
if (method.owner == ArrayClass)
method.name match {
if (symbol.owner == ArrayClass)
symbol.name match {
case nme.length => jArray.getLength(receiver)
case nme.apply => jArray.get(receiver, args(0).asInstanceOf[Int])
case nme.update => jArray.set(receiver, args(0).asInstanceOf[Int], args(1))
case _ => throw new Error(s"unexpected array method $method")
case _ => throw new Error(s"unexpected array method $symbol")
}
else
jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*)
}

private class JavaConstructorMirror(val method: MethodSymbol)
private class JavaConstructorMirror(val outer: AnyRef, val symbol: MethodSymbol)
extends MethodMirror {
override val receiver = null
override val receiver = outer
lazy val jconstr = {
val jconstr = constructorToJava(method)
val jconstr = constructorToJava(symbol)
if (!jconstr.isAccessible) jconstr.setAccessible(true)
jconstr
}
def apply(args: Any*): Any = jconstr.newInstance(args.asInstanceOf[Seq[AnyRef]]: _*)
def apply(args: Any*): Any = {
val effectiveArgs =
if (outer == null) args.asInstanceOf[Seq[AnyRef]]
else outer +: args.asInstanceOf[Seq[AnyRef]]
jconstr.newInstance(effectiveArgs: _*)
}
}


private abstract class JavaTemplateMirror
extends TemplateMirror {
def outer: AnyRef
def erasure: ClassSymbol
lazy val runtimeClass = classToJava(erasure)
lazy val signature = typeToScala(runtimeClass)
}

private class JavaClassMirror(val symbol: ClassSymbol)
private class JavaClassMirror(val outer: AnyRef, val symbol: ClassSymbol)
extends JavaTemplateMirror with ClassMirror {
def erasure = symbol
def isStatic = false
def reflectConstructor(constructor: MethodSymbol) = new JavaConstructorMirror(constructor)
def reflectConstructor(constructor: MethodSymbol) = new JavaConstructorMirror(outer, constructor)
def companion: Option[ModuleMirror] = symbol.companionModule match {
case module: ModuleSymbol => Some(new JavaModuleMirror(module))
case module: ModuleSymbol => Some(new JavaModuleMirror(outer, module))
case _ => None
}
}

private class JavaModuleMirror(val symbol: ModuleSymbol)
private class JavaModuleMirror(val outer: AnyRef, val symbol: ModuleSymbol)
extends JavaTemplateMirror with ModuleMirror {
def erasure = symbol.moduleClass.asClassSymbol
def isStatic = true
def instance = singletonInstance(classLoader, symbol.fullName)
def instance = {
if (!symbol.owner.isPackageClass) throw new Error("inner and nested modules are not supported yet")
singletonInstance(classLoader, symbol.fullName)
}
def companion: Option[ClassMirror] = symbol.companionClass match {
case cls: ClassSymbol => Some(new JavaClassMirror(cls))
case cls: ClassSymbol => Some(new JavaClassMirror(outer, cls))
case _ => None
}
}
@@ -929,7 +955,10 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym
def constructorToJava(constr: MethodSymbol): jConstructor[_] = constructorCache.toJava(constr) {
val jclazz = classToJava(constr.owner.asClassSymbol)
val paramClasses = transformedType(constr).paramTypes map typeToJavaClass
jclazz getConstructor (paramClasses: _*)
val effectiveParamClasses =
if (!constr.owner.owner.isStaticOwner) jclazz.getEnclosingClass +: paramClasses
else paramClasses
jclazz getConstructor (effectiveParamClasses: _*)
}

private def jArrayClass(elemClazz: jClass[_]): jClass[_] = {
@@ -5,7 +5,7 @@ object Test extends App {

val s = "hello world"
val m = cm.reflect(s)
val sc = m.reflectClass.symbol
val sc = m.symbol
val st = sc.asType
val meth = (st member newTermName("indexOf")).asTermSymbol
val IntType = definitions.IntClass.asType
@@ -0,0 +1,2 @@
this is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror
()
@@ -0,0 +1,32 @@
import scala.reflect.runtime.universe._
import scala.reflect.ClassTag

class Foo{
case class R(
sales : Int,
name : String
)

def foo = {
val expectedType = implicitly[TypeTag[R]]
val classTag = implicitly[ClassTag[R]]
val cl = classTag.runtimeClass.getClassLoader
val cm = runtimeMirror(cl)
val constructor = expectedType.tpe.member( nme.CONSTRUCTOR ).asMethodSymbol
val sig = constructor.typeSignature
val sym = cm.classSymbol( classTag.runtimeClass )
try {
val cls = cm.reflectClass( sym )
cls.reflectConstructor( constructor )( 5,"test" ).asInstanceOf[R]
println("this indicates a failure")
} catch {
case ex: Throwable =>
println(ex.getMessage)
}
}

}
object Test extends App{
val foo = new Foo
println( foo.foo )
}
@@ -0,0 +1 @@
R(5,test)

0 comments on commit abc1c0b

Please sign in to comment.
You can’t perform that action at this time.