diff --git a/src/compiler/scala/tools/nsc/tasty/TreeUnpickler.scala b/src/compiler/scala/tools/nsc/tasty/TreeUnpickler.scala index 864c4cedd5fc..6d38ff105bad 100644 --- a/src/compiler/scala/tools/nsc/tasty/TreeUnpickler.scala +++ b/src/compiler/scala/tools/nsc/tasty/TreeUnpickler.scala @@ -1148,6 +1148,9 @@ class TreeUnpickler[Tasty <: TastyUniverse]( tpd.Apply(fn, until(end)(readTerm()(argsCtx))) } case TYPEAPPLY => tpd.TypeApply(readTerm(), until(end)(readTpt())) + case APPLYsigpoly => + // this is skipped if it appears in parents, so only affects forced annotation trees + signaturePolymorphicIsUnsupported case TYPED => tpd.Typed(readTerm(), readTpt()) case IF => if (nextByte === INLINE) unsupportedTermTreeError("inline conditional expression") @@ -1241,6 +1244,9 @@ class TreeUnpickler[Tasty <: TastyUniverse]( */ private def abortMacroHole[T]: T = abortWith(msg = "Scala 3 macro hole in pickled TASTy") + private def signaturePolymorphicIsUnsupported[T](implicit ctx: Context): T = + unsupportedTermTreeError("signature polymorphic application") + private def metaprogrammingIsUnsupported[T](implicit ctx: Context): T = unsupportedError("Scala 3 metaprogramming features") diff --git a/src/compiler/scala/tools/tasty/TastyFormat.scala b/src/compiler/scala/tools/tasty/TastyFormat.scala index 0c06b899d389..8412767fdfa9 100644 --- a/src/compiler/scala/tools/tasty/TastyFormat.scala +++ b/src/compiler/scala/tools/tasty/TastyFormat.scala @@ -325,6 +325,7 @@ object TastyFormat { // final val ??? = 178 // final val ??? = 179 final val METHODtype = 180 + final val APPLYsigpoly = 181 final val MATCHtype = 190 final val MATCHtpt = 191 @@ -491,6 +492,7 @@ object TastyFormat { case BOUNDED => "BOUNDED" case APPLY => "APPLY" case TYPEAPPLY => "TYPEAPPLY" + case APPLYsigpoly => "APPLYsigpoly" case NEW => "NEW" case THROW => "THROW" case TYPED => "TYPED" diff --git a/test/tasty/neg/src-2/TestApplySigPoly.check b/test/tasty/neg/src-2/TestApplySigPoly.check new file mode 100644 index 000000000000..ccfb756803d9 --- /dev/null +++ b/test/tasty/neg/src-2/TestApplySigPoly.check @@ -0,0 +1,4 @@ +TestApplySigPoly_fail.scala:6: error: Unsupported Scala 3 signature polymorphic application in an annotation of method annotatedMethod; note that complex trees are not yet supported for Annotations; found in method annotatedMethod in object tastytest.ApplySigPoly. + def test = TestApplySigPolyPre.forceAnnots[ApplySigPoly.type, ApplySigPoly.boxAnnot] + ^ +1 error diff --git a/test/tasty/neg/src-2/TestApplySigPoly_fail.scala b/test/tasty/neg/src-2/TestApplySigPoly_fail.scala new file mode 100644 index 000000000000..d86094e4d4b1 --- /dev/null +++ b/test/tasty/neg/src-2/TestApplySigPoly_fail.scala @@ -0,0 +1,8 @@ +package tastytest + +object TestApplySigPoly { + + // force an annotation tree with an APPLYsigpoly node + def test = TestApplySigPolyPre.forceAnnots[ApplySigPoly.type, ApplySigPoly.boxAnnot] + +} diff --git a/test/tasty/neg/src-2/TestApplySigPoly_pre.scala b/test/tasty/neg/src-2/TestApplySigPoly_pre.scala new file mode 100644 index 000000000000..dc7d49bca384 --- /dev/null +++ b/test/tasty/neg/src-2/TestApplySigPoly_pre.scala @@ -0,0 +1,25 @@ +package tastytest + +import scala.language.experimental.macros + +import scala.reflect.macros.blackbox.Context + +object TestApplySigPolyPre { + + /** forces annotations of type `A` on methods from class `T` */ + def forceAnnots[T, A]: Unit = macro Macros.forceAnnotsImpl[T, A] + + object Macros { + def forceAnnotsImpl[T, A](c: Context)(implicit T: c.WeakTypeTag[T], A: c.WeakTypeTag[A]): c.Expr[Unit] = { + import c.universe._ + for { + method <- weakTypeOf[T].members.filter(_.isMethod) + annot <- method.annotations.find(_.tree.tpe =:= weakTypeOf[A]) + } { + annot.tree + } + c.Expr[Unit](q"()") + } + } + +} diff --git a/test/tasty/neg/src-3/ApplySigPoly.scala b/test/tasty/neg/src-3/ApplySigPoly.scala new file mode 100644 index 000000000000..046da9ff69a2 --- /dev/null +++ b/test/tasty/neg/src-3/ApplySigPoly.scala @@ -0,0 +1,20 @@ +package tastytest + +object ApplySigPoly { + + class Foo { + def foo(x: Int): Int = x + } + + private val lookup = java.lang.invoke.MethodHandles.lookup() + private val mt = java.lang.invoke.MethodType.methodType(classOf[Int], classOf[Int]); + + val mh = lookup.findVirtual(classOf[Foo], "foo", mt) + + val self = new Foo() + + class boxAnnot(val value: Int) extends scala.annotation.Annotation + + @boxAnnot(mh.invokeExact(self, 23): Int) + def annotatedMethod: Int = 23 +} diff --git a/test/tasty/run/src-2/tastytest/TestApplySigPoly.scala b/test/tasty/run/src-2/tastytest/TestApplySigPoly.scala new file mode 100644 index 000000000000..b77464610b05 --- /dev/null +++ b/test/tasty/run/src-2/tastytest/TestApplySigPoly.scala @@ -0,0 +1,14 @@ +package tastytest + +object TestApplySigPoly extends Suite("TestApplySigPoly") { + + test("construct class with APPLYsigpoly in parent") { + val subbox = new ApplySigPoly.SubBox() + assert(subbox.value == 23) + } + + test("call method with APPLYsigpoly in annotation") { + assert(ApplySigPoly.annotatedMethod == 23) + } + +} diff --git a/test/tasty/run/src-3/tastytest/ApplySigPoly.scala b/test/tasty/run/src-3/tastytest/ApplySigPoly.scala new file mode 100644 index 000000000000..4cdb4a4855d2 --- /dev/null +++ b/test/tasty/run/src-3/tastytest/ApplySigPoly.scala @@ -0,0 +1,25 @@ +package tastytest + +object ApplySigPoly { + + class Foo { + def foo(x: Int): Int = x + } + + private val lookup = java.lang.invoke.MethodHandles.lookup() + private val mt = java.lang.invoke.MethodType.methodType(classOf[Int], classOf[Int]); + + val mh = lookup.findVirtual(classOf[Foo], "foo", mt) + + class IntBox(val value: Int) + + val self = new Foo() + + // There should appear a APPLYsigpoly node in the parent of SubBox + class SubBox extends IntBox(mh.invokeExact(self, 23): Int) + + class boxAnnot(val value: Int) extends scala.annotation.Annotation + + @boxAnnot(mh.invokeExact(self, 23): Int) + def annotatedMethod: Int = 23 +}