summaryrefslogtreecommitdiff
path: root/test/files/run/reflection-valueclasses-magic.scala
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-08-05 20:02:39 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-08-06 23:09:31 +0200
commit3aa221e28c3ae0381b876448e3174f0c527e9abc (patch)
tree00567362f8608a5d62ef58881561c883c99ba445 /test/files/run/reflection-valueclasses-magic.scala
parent432d7b86cb7c46d0415b8c06bf8045e309c63f03 (diff)
downloadscala-3aa221e28c3ae0381b876448e3174f0c527e9abc.tar.gz
scala-3aa221e28c3ae0381b876448e3174f0c527e9abc.tar.bz2
scala-3aa221e28c3ae0381b876448e3174f0c527e9abc.zip
SI-6179 mirrors now work with value classes
mirrors now carry a class tag of the receiver, so that they can detect value classes being reflected upon and adjust accordingly (e.g. allow Int_+ for ints, but disallow it for Integers). Surprisingly enough derived value classes (SIP-15 guys that inherit from AnyVal) have been working all along, so no modification were required to fix them.
Diffstat (limited to 'test/files/run/reflection-valueclasses-magic.scala')
-rw-r--r--test/files/run/reflection-valueclasses-magic.scala110
1 files changed, 110 insertions, 0 deletions
diff --git a/test/files/run/reflection-valueclasses-magic.scala b/test/files/run/reflection-valueclasses-magic.scala
new file mode 100644
index 0000000000..f9feb2d504
--- /dev/null
+++ b/test/files/run/reflection-valueclasses-magic.scala
@@ -0,0 +1,110 @@
+import scala.reflect.runtime.universe._
+import scala.reflect.runtime.universe.definitions._
+import scala.reflect.runtime.{currentMirror => cm}
+import scala.reflect.ClassTag
+
+object Test extends App {
+ def key(sym: Symbol) = {
+ sym match {
+ // initialize parameter symbols
+ case meth: MethodSymbol => meth.params.flatten.map(_.typeSignature)
+ }
+ sym + ": " + sym.typeSignature
+ }
+
+ def convert(value: Any, tpe: Type) = {
+ import scala.runtime.BoxesRunTime._
+ if (tpe =:= typeOf[Byte]) toByte(value)
+ else if (tpe =:= typeOf[Short]) toShort(value)
+ else if (tpe =:= typeOf[Char]) toCharacter(value)
+ else if (tpe =:= typeOf[Int]) toInteger(value)
+ else if (tpe =:= typeOf[Long]) toLong(value)
+ else if (tpe =:= typeOf[Float]) toFloat(value)
+ else if (tpe =:= typeOf[Double]) toDouble(value)
+ else if (tpe =:= typeOf[String]) value.toString
+ else if (tpe =:= typeOf[Boolean]) value.asInstanceOf[Boolean]
+ else throw new Exception(s"not supported: value = $value, tpe = $tpe")
+ }
+
+ def test[T: ClassTag](tpe: Type, receiver: T, method: String, args: Any*) {
+ def wrap[T](op: => T) =
+ try {
+ var result = op.asInstanceOf[AnyRef]
+ if (scala.runtime.ScalaRunTime.isArray(result))
+ result = scala.runtime.ScalaRunTime.toObjectArray(result).toList
+ println(s"[${result.getClass}] =======> $result")
+ } catch {
+ case ex: Throwable =>
+ val realex = scala.reflect.runtime.ReflectionUtils.unwrapThrowable(ex)
+ println(realex.getClass + ": " + realex.getMessage)
+ }
+ val meth = tpe.declaration(newTermName(method).encodedName.toTermName)
+ val testees = if (meth.isMethod) List(meth.asMethod) else meth.asTerm.alternatives.map(_.asMethod)
+ testees foreach (testee => {
+ val convertedArgs = args.zipWithIndex.map { case (arg, i) => convert(arg, testee.params.flatten.apply(i).typeSignature) }
+ print(s"testing ${tpe.typeSymbol.name}.$method(${testee.params.flatten.map(_.typeSignature).mkString(','.toString)}) with receiver = $receiver and args = ${convertedArgs.map(arg => arg + ' '.toString + arg.getClass).toList}: ")
+ wrap(cm.reflect(receiver).reflectMethod(testee)(convertedArgs: _*))
+ })
+ }
+ def header(tpe: Type) {
+ println(s"============\n$tpe")
+ println("it's important to print the list of Byte's members")
+ println("if some of them change (possibly, adding and/or removing magic symbols), we must update this test")
+ tpe.members.toList.sortBy(key).foreach(sym => println(key(sym)))
+ }
+
+ def testNumeric[T: ClassTag](tpe: Type, value: T) {
+ header(tpe)
+ List("toByte", "toShort", "toChar", "toInt", "toLong", "toFloat", "toDouble") foreach (meth => test(tpe, value, meth))
+ test(tpe, value, "==", 2)
+ test(tpe, value, "!=", 2)
+ test(tpe, value, "<", 2)
+ test(tpe, value, "<=", 2)
+ test(tpe, value, ">", 2)
+ test(tpe, value, ">=", 2)
+ test(tpe, value, "+", 2)
+ test(tpe, value, "-", 2)
+ test(tpe, value, "*", 2)
+ test(tpe, value, "/", 2)
+ test(tpe, value, "%", 2)
+ }
+
+ def testIntegral[T: ClassTag](tpe: Type, value: T) {
+ testNumeric(tpe, value)
+ test(tpe, value, "unary_~")
+ test(tpe, value, "unary_+")
+ test(tpe, value, "unary_-")
+ test(tpe, value, "<<", 2)
+ test(tpe, value, ">>", 2)
+ test(tpe, value, ">>>", 2)
+ test(tpe, value, "|", 2)
+ test(tpe, value, "&", 2)
+ test(tpe, value, "^", 2)
+ }
+
+ def testBoolean() {
+ header(typeOf[Boolean])
+ test(typeOf[Boolean], true, "unary_!")
+ test(typeOf[Boolean], true, "==", true)
+ test(typeOf[Boolean], true, "!=", true)
+ test(typeOf[Boolean], true, "||", true)
+ test(typeOf[Boolean], true, "&&", true)
+ test(typeOf[Boolean], true, "|", true)
+ test(typeOf[Boolean], true, "&", true)
+ test(typeOf[Boolean], true, "^", true)
+ }
+
+ def testUnit() {
+ header(typeOf[Unit])
+ }
+
+ testNumeric(typeOf[Byte], 2.toByte)
+ testNumeric(typeOf[Short], 2.toShort)
+ testNumeric(typeOf[Char], 2.toChar)
+ testNumeric(typeOf[Int], 2.toInt)
+ testNumeric(typeOf[Long], 2.toLong)
+ testNumeric(typeOf[Float], 2.toFloat)
+ testNumeric(typeOf[Double], 2.toDouble)
+ testBoolean()
+ testUnit()
+} \ No newline at end of file