Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Improve internal representation of annotations when using defaults #22414

lrytz started this conversation in Feature Requests
Discussion options

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

  1. When compiling an annotation definition, default expressions are duplicated into a meta-annotation. So the ann definition above becomes
class ann(@annotation.meta.defaultArg(1) x: Int = 1, y: Int = 2) extends annotation.Annotation
  1. 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.

You must be logged in to vote

Replies: 2 comments

This comment has been hidden.

Comment options

this is correct in current Scala 3.

Not anymore 🥲 #22526

You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
2 participants

AltStyle によって変換されたページ (->オリジナル) /