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)
Oops, something went wrong.

0 comments on commit abc1c0b

Please sign in to comment.