-
Couldn't load subscription status.
- Fork 1.1k
Improve internal representation of annotations when using defaults #22414
-
When using defaults in an annotation, the dotc.core.Annotation representation represents missing arguments as calls to the corresponding $default$N methods.
Branch with test code: https://github.com/scala/scala3/compare/main...lrytz:scala3:sd884?expand=1
class ann(x: Int = 1, y: Int = 2) extends annotation.Annotation
For @ann(y = 22), annotation.arguments is
List(Select(Ident(ann),$lessinit$greater$default1ドル), NamedArg(y,Literal(22)))
scala/scala#10976 is improving this for Scala 2. (That PR is still under review and may change.)
Default expression ASTs
- When compiling an annotation definition, default expressions are duplicated into a meta-annotation. So the
anndefinition above becomes
class ann(@annotation.meta.defaultArg(1) x: Int = 1, y: Int = 2) extends annotation.Annotation
- When compiling an annotation expression, the defaults inserted are copies of the default expression AST, which is extracted out of the meta-annotation. So
@ann(y = 22)becomes@ann(x = 1, y = 22).
NOTE: In Scala 2, the default argument Tree inserted by the compiler (1 in the example) has an AnnotatedType, its type is tagged with the @defaultArg annotation. This is used in AnnotationInfo.argIsDefault, the method that tells whether an annotation argument was a default or provided in the source code.
User-defined annotation subclasses
The Scala 2 PR also introduces support for user-defined annoation subclasses. Example use case is class nodep extends nowarn("cat=deprecation").
To support that, a new method is added to the internal annotation representation: def argsForSuper(parent: Symbol): List[Tree]. Given an annotation @nodep def foo = ..., the call nodepAnnot.argsForSuper(nowarnClassSymbol) returns List(Literal("cat=deprecation")).
In order to support that, the argument expression AST passed to the super constructor are stored in a meta-annotation. The nodep definition above becomes
@annotation.meta.superArg("value", "cat=deprecation")
class nodep extends nowarn("cat=deprecation")
The implementation also supports forwarding parameters. For example
class sub(z: Int) extends ann(y = z)
becomes
@scala.annotation.meta.superArg("x", 1) // default
@scala.annotation.meta.superFwdArg("y", "z") // forwarded parameter
class sub(z: Int) extends ann(y = z)
Runtime uses of annotation classes
Note that annotation classes in Scala can be used as ordinary executable code. In this case they must be compiled the same as other classes, for example the following needs to evaluate 22 before the default:
scala> class ann(x: Int = 1.tap(println), y: Int) extends annotation.Annotation
// defined class ann
scala> new ann(y = 22.tap(println))
22
1
val res0: ann = ann@53d2b827
this is correct in current Scala 3.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 2
Replies: 2 comments
This comment has been hidden.
This comment has been hidden.
-
this is correct in current Scala 3.
Not anymore 🥲 #22526
Beta Was this translation helpful? Give feedback.
All reactions
-
😄 1