From 49883050d3e33ffa832fc63a9e09be95b5745d34 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Wed, 6 Jul 2022 17:39:17 +0200 Subject: [PATCH] handle multiple argument lists for annotations --- .../nsc/tasty/bridge/AnnotationOps.scala | 33 +++++++++++++++---- .../tools/nsc/tasty/bridge/TreeOps.scala | 2 +- .../tools/nsc/tasty/bridge/TypeOps.scala | 6 ++-- .../neg/src-2/TestSelectWithTarget.check | 7 ++++ .../neg/src-2/TestSelectWithTarget_fail.scala | 5 +++ test/tasty/neg/src-3/SelectWithTarget.scala | 12 +++++++ 6 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/compiler/scala/tools/nsc/tasty/bridge/AnnotationOps.scala b/src/compiler/scala/tools/nsc/tasty/bridge/AnnotationOps.scala index 4a7c35e3c5fb..5e48e9d82e8a 100644 --- a/src/compiler/scala/tools/nsc/tasty/bridge/AnnotationOps.scala +++ b/src/compiler/scala/tools/nsc/tasty/bridge/AnnotationOps.scala @@ -18,17 +18,38 @@ import scala.tools.nsc.tasty.TastyUniverse trait AnnotationOps { self: TastyUniverse => import self.{symbolTable => u} - private[bridge] final def mkAnnotation(tree: Tree): u.Annotation = { - def go(tpargs: List[Type], args: List[Tree], tree: Tree): u.Annotation = tree match { + trait ShowKind[T] { + def showKind(annot: String, t: T)(implicit ctx: Context): String + } + + object ShowKind { + implicit object ShowSymbol extends ShowKind[u.Symbol] { + def showKind(annot: String, t: u.Symbol)(implicit ctx: Context): String = s"$annot ${location(t)}" + } + implicit object ShowType extends ShowKind[u.Type] { + def showKind(annot: String, t: u.Type)(implicit ctx: Context): String = + s"type ${showType(t, wrap = false)} $annot of ${location(ctx.owner)}" + } + } + + private[bridge] final def mkAnnotation[T: ShowKind](tree: Tree, annotee: T)(implicit ctx: Context): u.Annotation = { + def go(tpargs: List[Type], args: List[List[Tree]], tree: Tree): u.Annotation = tree match { case u.Select(u.New(tpt), u.nme.CONSTRUCTOR) => val atp = if (tpargs.isEmpty) tpt.tpe else u.appliedType(tpt.tpe, tpargs) - u.AnnotationInfo(atp, args, Nil) + if (args.lengthIs > 1) { + val soFar = s"@${atp.typeSymbol.name.toString}${args.map(_.mkString("(", ", ", ")")).mkString("")}" + u.reporter.warning(u.NoPosition, + "Implementation limitation: multiple argument lists on annotations are\n"+ + "currently not supported; ignoring arguments " + args(1) + " on\n"+ + s"${implicitly[ShowKind[T]].showKind(soFar, annotee)}") + } + u.AnnotationInfo(atp, args.headOption.getOrElse(Nil), Nil) case u.TypeApply(pre, newTpArgs) if tpargs.isEmpty => go(newTpArgs.map(_.tpe), args, pre) case u.Apply(pre, Nil) => // skip the empty term param list go(tpargs, args, pre) - case u.Apply(pre, newArgs) if args.isEmpty => - go(tpargs, newArgs, pre) + case u.Apply(pre, newArgs) => + go(tpargs, newArgs :: args, pre) case _ => throw new Exception(s"unexpected annotation kind from TASTy: ${u.showRaw(tree)}") } @@ -55,7 +76,7 @@ trait AnnotationOps { self: TastyUniverse => new DeferredAnnotation(annotSym) { protected final def eager(annotee: Symbol)(implicit ctx: Context): u.AnnotationInfo = { val atree = tree(annotee)(ctx) - mkAnnotation(atree) + mkAnnotation(atree, annotee) } } } diff --git a/src/compiler/scala/tools/nsc/tasty/bridge/TreeOps.scala b/src/compiler/scala/tools/nsc/tasty/bridge/TreeOps.scala index 82d82af03a44..4220be32eb08 100644 --- a/src/compiler/scala/tools/nsc/tasty/bridge/TreeOps.scala +++ b/src/compiler/scala/tools/nsc/tasty/bridge/TreeOps.scala @@ -166,7 +166,7 @@ trait TreeOps { self: TastyUniverse => } } - def Annotated(tpt: Tree, annot: Tree): Tree = { + def Annotated(tpt: Tree, annot: Tree)(implicit ctx: Context): Tree = { if (annot.tpe.typeSymbol === defn.RepeatedAnnot && tpt.tpe.typeSymbol.isSubClass(u.definitions.SeqClass) && tpt.tpe.typeArgs.length == 1) { diff --git a/src/compiler/scala/tools/nsc/tasty/bridge/TypeOps.scala b/src/compiler/scala/tools/nsc/tasty/bridge/TypeOps.scala index 9231bcef98b2..fb96df3cd711 100644 --- a/src/compiler/scala/tools/nsc/tasty/bridge/TypeOps.scala +++ b/src/compiler/scala/tools/nsc/tasty/bridge/TypeOps.scala @@ -223,9 +223,9 @@ trait TypeOps { self: TastyUniverse => def IntersectionType(tps: Type*): Type = u.intersectionType(tps.toList) def IntersectionType(tps: List[Type]): Type = u.intersectionType(tps) - def AnnotatedType(tpe: Type, annot: Tree): Type = tpe match { - case u.AnnotatedType(annots, tpe) => u.AnnotatedType(annots :+ mkAnnotation(annot), tpe) - case _ => u.AnnotatedType(mkAnnotation(annot) :: Nil , tpe) + def AnnotatedType(tpe: Type, annot: Tree)(implicit ctx: Context): Type = tpe match { + case u.AnnotatedType(annots, tpe) => u.AnnotatedType(annots :+ mkAnnotation(annot, tpe), tpe) + case _ => u.AnnotatedType(mkAnnotation(annot, tpe) :: Nil , tpe) } def SuperType(thisTpe: Type, superTpe: Type): Type = u.SuperType(thisTpe, superTpe) diff --git a/test/tasty/neg/src-2/TestSelectWithTarget.check b/test/tasty/neg/src-2/TestSelectWithTarget.check index 2d2f16343965..398d235c3e13 100644 --- a/test/tasty/neg/src-2/TestSelectWithTarget.check +++ b/test/tasty/neg/src-2/TestSelectWithTarget.check @@ -1,4 +1,11 @@ TestSelectWithTarget_fail.scala:13: error: Unsupported Scala 3 selection of method foo with @targetName("fooString"); found in method selectFooString in object tastytest.SelectWithTarget. def test = TestSelectWithTargetPre.forceAnnots[SelectWithTarget.type, SelectWithTarget.defAnnot] ^ +warning: Implementation limitation: multiple argument lists on annotations are +currently not supported; ignoring arguments List(23) on +@mctorAnnot("a")(23) method methodWithAnnotMultipleParams in class tastytest.SelectWithTarget.MultiParamsAnnot +warning: Implementation limitation: multiple argument lists on annotations are +currently not supported; ignoring arguments List(23) on +type scala.Int @mctorAnnot("a")(23) of method foo in object tastytest.SelectWithTarget.MultiParamsAnnotTpe +2 warnings 1 error diff --git a/test/tasty/neg/src-2/TestSelectWithTarget_fail.scala b/test/tasty/neg/src-2/TestSelectWithTarget_fail.scala index 4ca4829cdd2c..9ef0dc27ca0d 100644 --- a/test/tasty/neg/src-2/TestSelectWithTarget_fail.scala +++ b/test/tasty/neg/src-2/TestSelectWithTarget_fail.scala @@ -12,4 +12,9 @@ object TestSelectWithTarget { // harmless unless we specificially need to analyse them. def test = TestSelectWithTargetPre.forceAnnots[SelectWithTarget.type, SelectWithTarget.defAnnot] + + def test2 = TestSelectWithTargetPre.forceAnnots[SelectWithTarget.MultiParamsAnnot, SelectWithTarget.mctorAnnot] + + def test3 = SelectWithTarget.MultiParamsAnnotTpe.foo + } diff --git a/test/tasty/neg/src-3/SelectWithTarget.scala b/test/tasty/neg/src-3/SelectWithTarget.scala index 42bf105ea222..73c556ca8699 100644 --- a/test/tasty/neg/src-3/SelectWithTarget.scala +++ b/test/tasty/neg/src-3/SelectWithTarget.scala @@ -6,9 +6,21 @@ object SelectWithTarget { class defAnnot(arg: Any) extends StaticAnnotation + class mctorAnnot(s: String)(i: Int) extends scala.annotation.Annotation + @defAnnot(Overloads.foo("hi")) def selectFooString: Int = 23 + class MultiParamsAnnot { + @mctorAnnot("a")(23) + def methodWithAnnotMultipleParams = 47 + } + + object MultiParamsAnnotTpe { + def foo: Int @mctorAnnot("a")(23) = 47 + } + + object Overloads { @targetName("fooString")