summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-09-23 14:07:22 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-09-28 14:21:45 +0200
commita6b81ac12a45866e97d30133c12dee775b93ea39 (patch)
tree89020413a56a36ebde3a02b99e4ec367f81cf33c
parent4e87654a9187fc65e5971580f4e25589fff052b9 (diff)
downloadscala-a6b81ac12a45866e97d30133c12dee775b93ea39.tar.gz
scala-a6b81ac12a45866e97d30133c12dee775b93ea39.tar.bz2
scala-a6b81ac12a45866e97d30133c12dee775b93ea39.zip
SI-6417 correctly reifies non-value types
If we're reifying non-value types (e.g. MethodTypes), we can't use them as type arguments for TypeTag/WeakTypeTag factory methods, otherwise the macro expansion won't typecheck: http://groups.google.com/group/scala-internals/browse_thread/thread/2d7bb85bfcdb2e2 This situation is impossible if one uses only reify and type tags, but c.reifyTree and c.reifyType exposes in the macro API let anyone feed anything into the reifier. Therefore I now check the tpe that is about to be used in TypeApply wrapping TypeTag/WeakTypeTag factory methods and replace it with AnyTpe if it doesn't fit.
-rw-r--r--src/compiler/scala/reflect/reify/utils/Extractors.scala14
-rw-r--r--test/files/run/macro-reify-type.check1
-rw-r--r--test/files/run/macro-reify-type.flags1
-rw-r--r--test/files/run/macro-reify-type/Macros_1.scala27
-rw-r--r--test/files/run/macro-reify-type/Test_2.scala21
5 files changed, 61 insertions, 3 deletions
diff --git a/src/compiler/scala/reflect/reify/utils/Extractors.scala b/src/compiler/scala/reflect/reify/utils/Extractors.scala
index b7206eda0e..523520749b 100644
--- a/src/compiler/scala/reflect/reify/utils/Extractors.scala
+++ b/src/compiler/scala/reflect/reify/utils/Extractors.scala
@@ -92,11 +92,19 @@ trait Extractors {
Block(List(universeAlias, mirrorAlias), wrappee)
}
+ private def mkTarg(tpe: Type): Tree = {
+ // if we're reifying a MethodType, we can't use it as a type argument for TypeTag ctor
+ // http://groups.google.com/group/scala-internals/browse_thread/thread/2d7bb85bfcdb2e2
+ val guineaPig = Apply(TypeApply(Select(Select(gen.mkRuntimeUniverseRef, nme.TypeTag), nme.apply), List(TypeTree(tpe))), List(Literal(Constant(null)), Literal(Constant(null))))
+ val isGoodTpe = typer.silent(_.typed(guineaPig)) match { case analyzer.SilentResultValue(_) => true; case _ => false }
+ TypeTree(if (isGoodTpe) tpe else AnyTpe)
+ }
+
object ReifiedTree {
def apply(universe: Tree, mirror: Tree, symtab: SymbolTable, rtree: Tree, tpe: Type, rtpe: Tree, concrete: Boolean): Tree = {
val tagFactory = if (concrete) nme.TypeTag else nme.WeakTypeTag
- val tagCtor = TypeApply(Select(Select(Ident(nme.UNIVERSE_SHORT), tagFactory), nme.apply), List(TypeTree(tpe)))
- val exprCtor = TypeApply(Select(Select(Ident(nme.UNIVERSE_SHORT), nme.Expr), nme.apply), List(TypeTree(tpe)))
+ val tagCtor = TypeApply(Select(Select(Ident(nme.UNIVERSE_SHORT), tagFactory), nme.apply), List(mkTarg(tpe)))
+ val exprCtor = TypeApply(Select(Select(Ident(nme.UNIVERSE_SHORT), nme.Expr), nme.apply), List(mkTarg(tpe)))
val tagArgs = List(Ident(nme.MIRROR_SHORT), mkCreator(tpnme.REIFY_TYPECREATOR_PREFIX, symtab, rtpe))
val unwrapped = Apply(Apply(exprCtor, List(Ident(nme.MIRROR_SHORT), mkCreator(tpnme.REIFY_TREECREATOR_PREFIX, symtab, rtree))), List(Apply(tagCtor, tagArgs)))
mkWrapper(universe, mirror, unwrapped)
@@ -123,7 +131,7 @@ trait Extractors {
object ReifiedType {
def apply(universe: Tree, mirror: Tree, symtab: SymbolTable, tpe: Type, rtpe: Tree, concrete: Boolean) = {
val tagFactory = if (concrete) nme.TypeTag else nme.WeakTypeTag
- val ctor = TypeApply(Select(Select(Ident(nme.UNIVERSE_SHORT), tagFactory), nme.apply), List(TypeTree(tpe)))
+ val ctor = TypeApply(Select(Select(Ident(nme.UNIVERSE_SHORT), tagFactory), nme.apply), List(mkTarg(tpe)))
val args = List(Ident(nme.MIRROR_SHORT), mkCreator(tpnme.REIFY_TYPECREATOR_PREFIX, symtab, rtpe))
val unwrapped = Apply(ctor, args)
mkWrapper(universe, mirror, unwrapped)
diff --git a/test/files/run/macro-reify-type.check b/test/files/run/macro-reify-type.check
new file mode 100644
index 0000000000..ea5e70e10d
--- /dev/null
+++ b/test/files/run/macro-reify-type.check
@@ -0,0 +1 @@
+[B, That](f: Int => B)(implicit bf: scala.collection.generic.CanBuildFrom[List[Int],B,That])That \ No newline at end of file
diff --git a/test/files/run/macro-reify-type.flags b/test/files/run/macro-reify-type.flags
new file mode 100644
index 0000000000..cd66464f2f
--- /dev/null
+++ b/test/files/run/macro-reify-type.flags
@@ -0,0 +1 @@
+-language:experimental.macros \ No newline at end of file
diff --git a/test/files/run/macro-reify-type/Macros_1.scala b/test/files/run/macro-reify-type/Macros_1.scala
new file mode 100644
index 0000000000..aeec9fc97c
--- /dev/null
+++ b/test/files/run/macro-reify-type/Macros_1.scala
@@ -0,0 +1,27 @@
+import scala.reflect.macros.Context
+import scala.reflect.runtime.{universe => ru}
+
+object StaticReflect {
+ def method[A](name: String): ru.Type = macro methodImpl[A]
+
+ def methodImpl[A: c.WeakTypeTag](c: Context)(name: c.Expr[String]): c.Expr[ru.Type] = {
+ import c.universe._
+
+ val nameName: TermName = name.tree match {
+ case Literal(Constant(str: String)) => newTermName(str)
+ case _ => c.error(c.enclosingPosition, s"Method name not constant.") ; return reify(ru.NoType)
+ }
+ val clazz = weakTypeOf[A]
+
+ clazz member nameName match {
+ case NoSymbol => c.error(c.enclosingPosition, s"No member called $nameName in $clazz.") ; reify(ru.NoType)
+ case member =>
+ val mtpe = member typeSignatureIn clazz
+ val mtag = c.reifyType(c.runtimeUniverse, Select(c.runtimeUniverse, newTermName("rootMirror")), mtpe)
+ val mtree = Select(mtag, newTermName("tpe"))
+
+ c.Expr[ru.Type](mtree)
+ }
+ }
+
+}
diff --git a/test/files/run/macro-reify-type/Test_2.scala b/test/files/run/macro-reify-type/Test_2.scala
new file mode 100644
index 0000000000..9beaf98681
--- /dev/null
+++ b/test/files/run/macro-reify-type/Test_2.scala
@@ -0,0 +1,21 @@
+import StaticReflect._
+
+object Test extends App {
+ //println(method[List[Int]]("distinct"))
+ println(method[List[Int]]("map"))
+ //val $u: scala.reflect.runtime.universe.type = scala.reflect.runtime.universe;
+ //val $m: $u.Mirror = scala.reflect.runtime.universe.rootMirror;
+ //import $u._, $m._, Flag._
+ //val tpe = {
+ // val symdef$B2 = build.newNestedSymbol(build.selectTerm(staticClass("scala.collection.TraversableLike"), "map"), newTypeName("B"), NoPosition, DEFERRED | PARAM, false);
+ // val symdef$That2 = build.newNestedSymbol(build.selectTerm(staticClass("scala.collection.TraversableLike"), "map"), newTypeName("That"), NoPosition, DEFERRED | PARAM, false);
+ // val symdef$f2 = build.newNestedSymbol(build.selectTerm(staticClass("scala.collection.TraversableLike"), "map"), newTermName("f"), NoPosition, PARAM, false);
+ // val symdef$bf2 = build.newNestedSymbol(build.selectTerm(staticClass("scala.collection.TraversableLike"), "map"), newTermName("bf"), NoPosition, IMPLICIT | PARAM, false);
+ // build.setTypeSignature(symdef$B2, TypeBounds(staticClass("scala.Nothing").asType.toTypeConstructor, staticClass("scala.Any").asType.toTypeConstructor));
+ // build.setTypeSignature(symdef$That2, TypeBounds(staticClass("scala.Nothing").asType.toTypeConstructor, staticClass("scala.Any").asType.toTypeConstructor));
+ // build.setTypeSignature(symdef$f2, TypeRef(ThisType(staticPackage("scala").asModule.moduleClass), staticClass("scala.Function1"), List(staticClass("scala.Int").asType.toTypeConstructor, TypeRef(NoPrefix, symdef$B2, List()))));
+ // build.setTypeSignature(symdef$bf2, TypeRef(ThisType(staticPackage("scala.collection.generic").asModule.moduleClass), staticClass("scala.collection.generic.CanBuildFrom"), List(TypeRef(ThisType(staticPackage("scala.collection.immutable").asModule.moduleClass), staticClass("scala.collection.immutable.List"), List(staticClass("scala.Int").asType.toTypeConstructor)), TypeRef(NoPrefix, symdef$B2, List()), TypeRef(NoPrefix, symdef$That2, List()))));
+ // PolyType(List(symdef$B2, symdef$That2), MethodType(List(symdef$f2), MethodType(List(symdef$bf2), TypeRef(NoPrefix, symdef$That2, List()))))
+ //}
+ //println(tpe)
+} \ No newline at end of file