From cdac66f750acb6fbf000215b8534f27f51da00a3 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Thu, 5 Sep 2013 14:38:31 +0200 Subject: 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. --- .../tools/reflect/quasiquotes/Placeholders.scala | 7 ++--- .../scala/tools/reflect/quasiquotes/Reifiers.scala | 35 +++++++--------------- src/reflect/scala/reflect/api/BuildUtils.scala | 4 ++- .../scala/reflect/internal/BuildUtils.scala | 15 +++++----- .../quasiquotes/DefinitionConstructionProps.scala | 10 +++++++ 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 -- cgit v1.2.3