summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDen Shabalin <den.shabalin@gmail.com>2013-09-05 14:38:31 +0200
committerDen Shabalin <den.shabalin@gmail.com>2013-09-05 20:42:11 +0200
commitcdac66f750acb6fbf000215b8534f27f51da00a3 (patch)
tree48a977d3a0a575b3c1a76636a5360760de923a3f
parent230f36d9ca99abe33f4379ffd573702b2671f83a (diff)
downloadscala-cdac66f750acb6fbf000215b8534f27f51da00a3.tar.gz
scala-cdac66f750acb6fbf000215b8534f27f51da00a3.tar.bz2
scala-cdac66f750acb6fbf000215b8534f27f51da00a3.zip
streamline implementation of annotation splicing
Syntax spec mislead me to believe that annotation can't have type parameters or multiple argument lists... I guess the lesson here is don't trust the spec.
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala7
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala35
-rw-r--r--src/reflect/scala/reflect/api/BuildUtils.scala4
-rw-r--r--src/reflect/scala/reflect/internal/BuildUtils.scala15
-rw-r--r--test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala10
5 files changed, 34 insertions, 37 deletions
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
index c136e6d785..e20d98c0f1 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
@@ -92,10 +92,9 @@ trait Placeholders { self: Quasiquotes =>
}
}
- object AnnotPlaceholder {
- def unapply(tree: Tree): Option[(Tree, Location, Cardinality, List[Tree])] = tree match {
- case Apply(Select(New(Placeholder(tree, loc, card)), nme.CONSTRUCTOR), args) => Some(tree, loc, card, args)
- case _ => None
+ object AnnotPlaceholder extends HolePlaceholder {
+ def matching = {
+ case Apply(Select(New(Ident(name)), nme.CONSTRUCTOR), Nil) => name
}
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
index 069ef09bc7..af4e34536c 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
@@ -130,6 +130,8 @@ trait Reifiers { self: Quasiquotes =>
def reifyEarlyDef(tree: Tree) = tree
+ def reifyAnnotation(tree: Tree) = tree
+
/** Splits list into a list of groups where subsequent elements are considered
* similar by the corresponding function.
*
@@ -189,7 +191,12 @@ trait Reifiers { self: Quasiquotes =>
reify(_)
}
- def reifyAnnotList(annots: List[Tree]): Tree
+ def reifyAnnotList(annots: List[Tree]): Tree = reifyMultiCardinalityList(annots) {
+ case AnnotPlaceholder(tree, _, DotDot) => reifyAnnotation(tree)
+ } {
+ case AnnotPlaceholder(tree, UnknownLocation | TreeLocation(_), NoDot) => reifyAnnotation(tree)
+ case other => reify(other)
+ }
// These are explicit flags except those that are used
// to overload the same tree for two different concepts:
@@ -236,19 +243,6 @@ trait Reifiers { self: Quasiquotes =>
tail.foldLeft[Tree](reifyGroup(head)) { (tree, lst) => Apply(Select(tree, nme.PLUSPLUS), List(reifyGroup(lst))) }
}
- override def reifyAnnotList(annots: List[Tree]): Tree = reifyMultiCardinalityList(annots) {
- case AnnotPlaceholder(tree, _, DotDot, args) =>
- val x: TermName = c.freshName()
- val xToAnnotationCtor = Function(
- List(ValDef(Modifiers(PARAM), x, TypeTree(), EmptyTree)),
- mirrorBuildCall(nme.mkAnnotation, Ident(x), reify(args)))
- Apply(Select(tree, nme.map), List(xToAnnotationCtor))
- } {
- case AnnotPlaceholder(tree, _: TreeLocation, _, args) =>
- mirrorBuildCall(nme.mkAnnotation, tree, reify(args))
- case other => reify(other)
- }
-
override def reifyModifiers(m: Modifiers) =
if (m == NoMods) super.reifyModifiers(m)
else {
@@ -283,6 +277,8 @@ trait Reifiers { self: Quasiquotes =>
override def reifyRefineStat(tree: Tree) = mirrorBuildCall(nme.mkRefineStat, tree)
override def reifyEarlyDef(tree: Tree) = mirrorBuildCall(nme.mkEarlyDef, tree)
+
+ override def reifyAnnotation(tree: Tree) = mirrorBuildCall(nme.mkAnnotation, tree)
}
class UnapplyReifier extends Reifier {
@@ -301,17 +297,6 @@ trait Reifiers { self: Quasiquotes =>
mkList(xs.map(fallback))
}
- override def reifyAnnotList(annots: List[Tree]): Tree = reifyMultiCardinalityList(annots) {
- case AnnotPlaceholder(tree, _, DotDot, Nil) => tree
- } {
- case AnnotPlaceholder(tree, _, NoDot, Nil) => tree
- case AnnotPlaceholder(tree, _, NoDot, args) =>
- val selectCONSTRUCTOR = Apply(Select(u, nme.Select), List(Apply(Select(u, nme.New), List(tree)), Select(Select(u, nme.nmeNme), nme.nmeCONSTRUCTOR)))
- Apply(Select(u, nme.Apply), List(selectCONSTRUCTOR, reify(args)))
- case other =>
- reify(other)
- }
-
override def reifyModifiers(m: Modifiers) =
if (m == NoMods) super.reifyModifiers(m)
else {
diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala
index ee6515b547..60c2a81947 100644
--- a/src/reflect/scala/reflect/api/BuildUtils.scala
+++ b/src/reflect/scala/reflect/api/BuildUtils.scala
@@ -72,7 +72,9 @@ private[reflect] trait BuildUtils { self: Universe =>
def setSymbol[T <: Tree](tree: T, sym: Symbol): T
- def mkAnnotation(tree: Tree, args: List[Tree]): Tree
+ def mkAnnotation(tree: Tree): Tree
+
+ def mkAnnotation(trees: List[Tree]): List[Tree]
def mkRefineStat(stat: Tree): Tree
diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala
index 2376787116..06a6e10c30 100644
--- a/src/reflect/scala/reflect/internal/BuildUtils.scala
+++ b/src/reflect/scala/reflect/internal/BuildUtils.scala
@@ -61,15 +61,16 @@ trait BuildUtils { self: SymbolTable =>
def setSymbol[T <: Tree](tree: T, sym: Symbol): T = { tree.setSymbol(sym); tree }
- def mkAnnotation(tree: Tree, args: List[Tree]): Tree = tree match {
- case ident: Ident => Apply(self.Select(New(ident), nme.CONSTRUCTOR: TermName), args)
- case call @ Apply(Select(New(ident: Ident), nme.CONSTRUCTOR), _) =>
- if (args.nonEmpty)
- throw new IllegalArgumentException("Can't splice annotation that already contains args with extra args, consider merging these lists together")
- call
- case _ => throw new IllegalArgumentException(s"Tree ${showRaw(tree)} isn't a correct representation of annotation, consider passing Ident as a first argument")
+ def mkAnnotation(tree: Tree): Tree = tree match {
+ case SyntacticNew(Nil, SyntacticApplied(SyntacticTypeApplied(_, _), _) :: Nil, emptyValDef, Nil) =>
+ tree
+ case _ =>
+ throw new IllegalArgumentException(s"Tree ${showRaw(tree)} isn't a correct representation of annotation." +
+ """Consider reformatting it into a q"new $name[..$targs](...$argss)" shape""")
}
+ def mkAnnotation(trees: List[Tree]): List[Tree] = trees.map(mkAnnotation)
+
def mkVparamss(argss: List[List[ValDef]]): List[List[ValDef]] = argss.map(_.map(mkParam))
def mkParam(vd: ValDef): ValDef = {
diff --git a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala
index 96105b9581..153e23d947 100644
--- a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala
@@ -280,4 +280,14 @@ trait MethodConstruction { self: QuasiquoteProperties =>
q"@$a(y) def foo"
}
}
+
+ property("splice annotation with targs") = test {
+ val a = q"new Foo[A, B]"
+ assertEqAst(q"@$a def foo", "@Foo[A,B] def foo")
+ }
+
+ property("splice annotation with multiple argument lists") = test{
+ val a = q"new Foo(a)(b)"
+ assertEqAst(q"@$a def foo", "@Foo(a)(b) def foo")
+ }
} \ No newline at end of file