0

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

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
Alex Savitsky
  • 2,306
  • 5
  • 24
  • 30
  • https://stackoverflow.com/questions/14034142/how-do-i-access-default-parameter-values-via-scala-reflection https://stackoverflow.com/questions/55032173/how-to-use-named-arguments-in-scala-user-defined-annotations/ – Dmytro Mitin Aug 31 '22 at 17:38
  • Does this answer your question? – Dmytro Mitin Sep 01 '22 at 10:57

0 Answers0