Skip to content

Commit

Permalink
handle multiple argument lists for annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
bishabosha committed Jul 7, 2022
1 parent d00ade6 commit d7f0b8b
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 10 deletions.
33 changes: 27 additions & 6 deletions src/compiler/scala/tools/nsc/tasty/bridge/AnnotationOps.scala
Expand Up @@ -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)}")
}
Expand All @@ -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)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/tasty/bridge/TreeOps.scala
Expand Up @@ -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) {
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/scala/tools/nsc/tasty/bridge/TypeOps.scala
Expand Up @@ -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)
Expand Down
7 changes: 7 additions & 0 deletions 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
5 changes: 5 additions & 0 deletions test/tasty/neg/src-2/TestSelectWithTarget_fail.scala
Expand Up @@ -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

}
12 changes: 12 additions & 0 deletions test/tasty/neg/src-3/SelectWithTarget.scala
Expand Up @@ -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")
Expand Down

0 comments on commit d7f0b8b

Please sign in to comment.