Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow macro annotation to transform companion #19676

Closed
nicolasstucki opened this issue Feb 13, 2024 · 1 comment · Fixed by #19677
Closed

Allow macro annotation to transform companion #19676

nicolasstucki opened this issue Feb 13, 2024 · 1 comment · Fixed by #19677

Comments

@nicolasstucki
Copy link
Contributor

With the current definition of macro annotations, we can only modify the annotated definition. There exist use cases where we want to annotate a class and add/transform/check methods in the companion object, or vice-versa.

Proposed change

package scala.annotation
import scala.quoted.*

trait MacroAnnotation extends StaticAnnotation:
  /** Transforms a tree `definition` and optionally adds new definitions.
   *
   *  This method takes as an argument the `definition` that will be transformed by the macro annotation.
   *  It returns a non-empty list containing the modified version of the annotated definition.
   *  The new tree for the definition must use the original symbol.
   *  New definitions can be added to the list before or after the transformed definitions, this order
   *  will be retained. New definitions will not be visible from outside the macro expansion.
   *
+  *  For classes or objects annotated with a macro annotation, we also provide an optional `companion`
+  *  containing the class or object companion. It is `None` if the definition does not have a companion.
+  *  If `definition` represents the class, then the companion is the module class of the object; if the
+  *  `definition` is a module class, then the companion is the class itself. This companion can be
+  *  transformed in the same way as the `definition`. If transformed it should be added to the resulting
+  *  list of definitions.
   *
   *  ...
   */
  def transform(using Quotes)(
    definition: quotes.reflect.Definition
+   companion: Option[quotes.reflect.Definition]
  ): List[quotes.reflect.Definition]
@nicolasstucki
Copy link
Contributor Author

While we are allowed to brack this API at any time because it is experimental, I would suggest changing it in the next minor release. This is to avoid confusion and unpredictability for users experimenting with this feature.

nicolasstucki added a commit that referenced this issue Apr 30, 2024
### Allow MacroAnnotations to update the companion of a definition

We extend the MacroAnnotation api to allow to modify the companion of a
class or an object.

### Specification

1. Order of expansion

- We expand the definitions in program order. 
- We expand the annotations of the outer scope first, then we expand the
inner definitions.
- Annotations are expanded from the outer annotation to the inner
annotation.

In the following example, we expand the annotations in this order: `a1`,
`a2`, `a3`.

```scala
@A1 @a2
class Foo:
  @A3 def foo = ???
```
2. Expansion of the companion

We always expand the latest available tree. If an annotation defined on
`class Foo` changes its companion (`object Foo`) and the `class` is
defined before `object`, the expansion of the annotations on the
`object` will be performed on the result of the expansion of `class`.

3. The program order is maintained

We maintain the program order in the definitions that were expanded.

4. Backtrack and reprocess

Example:

```scala
@A1 class Foo
@a2 object Foo
```
If the `@a2` annotation changes the definitions in `class Foo`, we will
rerun the algorithm on the result of this new expansion. Please note
that we don't allow to generate code with MacroAnnotations, the reason
for rerunning the algorithm is to expand and inline possible macros that
we generated.

---
Closes #19676
@Kordyjan Kordyjan added this to the 3.5.0 milestone May 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment