I have a Scala annotation with parameters, some with default values:
case class A(x: String, y: Option[String] = None, z: Option[Boolean] = None)
extends scala.annotation.StaticAnnotation
The goal is to annotate classes with this, and collect annotation parameters at runtime.
If I specify annotation parameters using positional notation, things work fine:
@A("xx", None, Some(true)) case class X()
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val m = runtimeMirror(getClass.getClassLoader)
val t = m.mkToolBox()
val x = typeOf[X].typeSymbol.asClass.annotations.find(_.tree.tpe =:= typeOf[A]).get
println(t.eval(t.untypecheck(x.tree)).asInstanceOf[A])
This would print A(xx,None,Some(true))
, as it should.
The following, however, would not work:
@A("x", z = Some(true)) case class Y()
val y = typeOf[Y].typeSymbol.asClass.annotations.find(_.tree.tpe =:= typeOf[A]).get
println(t.eval(t.untypecheck(y.tree)).asInstanceOf[A])
it would result in an exception I've never seen before:
java.lang.AssertionError: assertion failed: unsafe symbol x$3 (child of <none>) in runtime reflection universe
at scala.reflect.internal.Symbols$Symbol.<init>(Symbols.scala:205)
at scala.reflect.internal.Symbols$TermSymbol.<init>(Symbols.scala:2768)
at scala.reflect.internal.Symbols$StubTermSymbol.<init>(Symbols.scala:3524)
at scala.reflect.internal.Symbols$class.newStubSymbol(Symbols.scala:192)
at scala.reflect.internal.SymbolTable.newStubSymbol(SymbolTable.scala:16)
at scala.reflect.internal.Symbols$Symbol.newStubSymbol(Symbols.scala:521)
at scala.reflect.internal.pickling.UnPickler$Scan.readExtSymbol$1(UnPickler.scala:258)
at scala.reflect.internal.pickling.UnPickler$Scan.readSymbol(UnPickler.scala:286)
at scala.reflect.internal.pickling.UnPickler$Scan.readSymbolRef(UnPickler.scala:651)
at scala.reflect.internal.pickling.UnPickler$Scan.readNonEmptyTree(UnPickler.scala:610)
at scala.reflect.internal.pickling.UnPickler$Scan.readTree(UnPickler.scala:623)
at scala.reflect.internal.pickling.UnPickler$Scan$$anonfun$readAnnotArg$1.apply(UnPickler.scala:471)
at scala.reflect.internal.pickling.UnPickler$Scan$$anonfun$readAnnotArg$1.apply(UnPickler.scala:471)
at scala.reflect.internal.pickling.UnPickler$Scan.at(UnPickler.scala:179)
at scala.reflect.internal.pickling.UnPickler$Scan.readAnnotArg(UnPickler.scala:471)
at scala.reflect.internal.pickling.UnPickler$Scan.readAnnotationInfo(UnPickler.scala:505)
at scala.reflect.internal.pickling.UnPickler$Scan.readSymbolAnnotation(UnPickler.scala:517)
at scala.reflect.internal.pickling.UnPickler$Scan.run(UnPickler.scala:97)
at scala.reflect.internal.pickling.UnPickler.unpickle(UnPickler.scala:38)
at scala.reflect.runtime.JavaMirrors$JavaMirror.unpickleClass(JavaMirrors.scala:619)
at scala.reflect.runtime.SymbolLoaders$TopClassCompleter$$anonfun$complete$1.apply$mcV$sp(SymbolLoaders.scala:28)
at scala.reflect.runtime.SymbolLoaders$TopClassCompleter$$anonfun$complete$1.apply(SymbolLoaders.scala:25)
at scala.reflect.runtime.SymbolLoaders$TopClassCompleter$$anonfun$complete$1.apply(SymbolLoaders.scala:25)
at scala.reflect.internal.SymbolTable.slowButSafeEnteringPhaseNotLaterThan(SymbolTable.scala:263)
at scala.reflect.runtime.SymbolLoaders$TopClassCompleter.complete(SymbolLoaders.scala:25)
at scala.reflect.internal.Symbols$Symbol.info(Symbols.scala:1535)
at scala.reflect.runtime.SynchronizedSymbols$SynchronizedSymbol$$anon$8.scala$reflect$runtime$SynchronizedSymbols$SynchronizedSymbol$$super$info(SynchronizedSymbols.scala:168)
at scala.reflect.runtime.SynchronizedSymbols$SynchronizedSymbol$$anonfun$info$1.apply(SynchronizedSymbols.scala:127)
at scala.reflect.runtime.SynchronizedSymbols$SynchronizedSymbol$$anonfun$info$1.apply(SynchronizedSymbols.scala:127)
at scala.reflect.runtime.Gil$class.gilSynchronized(Gil.scala:19)
at scala.reflect.runtime.JavaUniverse.gilSynchronized(JavaUniverse.scala:16)
at scala.reflect.runtime.SynchronizedSymbols$SynchronizedSymbol$class.gilSynchronizedIfNotThreadsafe(SynchronizedSymbols.scala:123)
at scala.reflect.runtime.SynchronizedSymbols$SynchronizedSymbol$$anon$8.gilSynchronizedIfNotThreadsafe(SynchronizedSymbols.scala:168)
at scala.reflect.runtime.SynchronizedSymbols$SynchronizedSymbol$class.info(SynchronizedSymbols.scala:127)
at scala.reflect.runtime.SynchronizedSymbols$SynchronizedSymbol$$anon$8.info(SynchronizedSymbols.scala:168)
at scala.reflect.internal.Symbols$Symbol.initialize(Symbols.scala:1680)
at scala.reflect.internal.Symbols$Symbol.annotations(Symbols.scala:1847)
at test.TestAnnotation$.delayedEndpoint$test$TestAnnotation$1(TestAnnotation.scala:18)
at test.TestAnnotation$delayedInit$body.apply(TestAnnotation.scala:12)
at scala.Function0$class.apply$mcV$sp(Function0.scala:34)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
at scala.App$$anonfun$main$1.apply(App.scala:76)
at scala.App$$anonfun$main$1.apply(App.scala:76)
at scala.collection.immutable.List.foreach(List.scala:392)
at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35)
at scala.App$class.main(App.scala:76)
at test.TestAnnotation$.main(TestAnnotation.scala:12)
at test.TestAnnotation.main(TestAnnotation.scala)
Exception in thread "main" java.lang.RuntimeException: error reading Scala signature of test.Y: assertion failed: unsafe symbol x$3 (child of <none>) in runtime reflection universe
at scala.reflect.internal.pickling.UnPickler.unpickle(UnPickler.scala:46)
at scala.reflect.runtime.JavaMirrors$JavaMirror.unpickleClass(JavaMirrors.scala:619)
at scala.reflect.runtime.SymbolLoaders$TopClassCompleter$$anonfun$complete$1.apply$mcV$sp(SymbolLoaders.scala:28)
at scala.reflect.runtime.SymbolLoaders$TopClassCompleter$$anonfun$complete$1.apply(SymbolLoaders.scala:25)
at scala.reflect.runtime.SymbolLoaders$TopClassCompleter$$anonfun$complete$1.apply(SymbolLoaders.scala:25)
at scala.reflect.internal.SymbolTable.slowButSafeEnteringPhaseNotLaterThan(SymbolTable.scala:263)
at scala.reflect.runtime.SymbolLoaders$TopClassCompleter.complete(SymbolLoaders.scala:25)
at scala.reflect.internal.Symbols$Symbol.info(Symbols.scala:1535)
at scala.reflect.runtime.SynchronizedSymbols$SynchronizedSymbol$$anon$8.scala$reflect$runtime$SynchronizedSymbols$SynchronizedSymbol$$super$info(SynchronizedSymbols.scala:168)
at scala.reflect.runtime.SynchronizedSymbols$SynchronizedSymbol$$anonfun$info$1.apply(SynchronizedSymbols.scala:127)
at scala.reflect.runtime.SynchronizedSymbols$SynchronizedSymbol$$anonfun$info$1.apply(SynchronizedSymbols.scala:127)
at scala.reflect.runtime.Gil$class.gilSynchronized(Gil.scala:19)
at scala.reflect.runtime.JavaUniverse.gilSynchronized(JavaUniverse.scala:16)
at scala.reflect.runtime.SynchronizedSymbols$SynchronizedSymbol$class.gilSynchronizedIfNotThreadsafe(SynchronizedSymbols.scala:123)
at scala.reflect.runtime.SynchronizedSymbols$SynchronizedSymbol$$anon$8.gilSynchronizedIfNotThreadsafe(SynchronizedSymbols.scala:168)
at scala.reflect.runtime.SynchronizedSymbols$SynchronizedSymbol$class.info(SynchronizedSymbols.scala:127)
at scala.reflect.runtime.SynchronizedSymbols$SynchronizedSymbol$$anon$8.info(SynchronizedSymbols.scala:168)
at scala.reflect.internal.Symbols$Symbol.initialize(Symbols.scala:1680)
at scala.reflect.internal.Symbols$Symbol.annotations(Symbols.scala:1847)
at test.TestAnnotation$.delayedEndpoint$test$TestAnnotation$1(TestAnnotation.scala:18)
at test.TestAnnotation$delayedInit$body.apply(TestAnnotation.scala:12)
at scala.Function0$class.apply$mcV$sp(Function0.scala:34)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
at scala.App$$anonfun$main$1.apply(App.scala:76)
at scala.App$$anonfun$main$1.apply(App.scala:76)
at scala.collection.immutable.List.foreach(List.scala:392)
at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35)
at scala.App$class.main(App.scala:76)
at test.TestAnnotation$.main(TestAnnotation.scala:12)
at test.TestAnnotation.main(TestAnnotation.scala)
As soon as I switch back to the positional arguments, things start working again.
Any idea on what am I facing here?
EDIT: Tried this with Scala 2.11 and 2.13, the failure and exception is consistent for both versions