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

Fix macro annotations spliceOwner #16513

Merged

Conversation

nicolasstucki
Copy link
Contributor

The splice owner of the macro annotation should be the owner of the
annotated definition. The issue was that if that owner was a class
quotes unpickled with this context accidentally entered definitions
in the quotes into the class. Now we unpickle these definitions using
a dummy val owner (similar to the LocalDummy).


quotePickling.println(i"**** unpickled quote\n$tree")
var tree = unpickler.tree
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No var needed here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops

// When a quote is unpickled with a Quotes context that that has a class `spliceOwner`
// we need to use a dummy owner to unpickle it. Otherwise any definitions defined
// in the quoted block would be accidentally entered in the class.
// This owner is replaced with the correct owner when at the splice site.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that in callMacro? Maybe refer to it explicitly, then it's clearer where the owner gets replaced.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is in this same file in quotedExprToTree and quotedTypeToTree. I added a reference in the comment and explained a bit more.

@@ -31,14 +31,20 @@ trait MacroAnnotation extends StaticAnnotation:
* def transform(using Quotes)(tree: quotes.reflect.Definition): List[quotes.reflect.Definition] =
* import quotes.reflect._
* tree match
* case DefDef(name, TermParamClause(param :: Nil) :: Nil, tpt, Some(rhsTree)) =>
* (Ref(param.symbol).asExpr, rhsTree.asExpr) match
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are all these macros here and in run-macros changed? Does the old implementation not work anymore?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, the old implementation still works but is suboptimal and has a bug. It had three issues:

  • With quotes getting unpickled in with the wrong owner each splice has the potential to trigger an owner change.
  • If users would assemble the expression using reflection they would need extra explicit changeOwner calls
  • To recover the type of the signature we should look at the signature and not the terms. In the previous version, we had an accidental term reference to the parameter of the annotated def that leaked into the new field.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make the context changes simpler, I plan to add a method like inContext.

Something like

val rhs = inQuotes(owner){ '{...} }

@odersky odersky assigned nicolasstucki and unassigned odersky Dec 14, 2022
@nicolasstucki nicolasstucki force-pushed the macro-annotations-fix-splice-owner branch from c5050cd to 8d45fcf Compare December 15, 2022 09:17
The splice owner of the macro annotation should be the owner of the
annotated definition. The issue was that if that owner was a class
quotes unpickled with this context accidentally entered definitions
in the quotes into the class. Now we unpickle these definitions using
a dummy val owner (similar to the LocalDummy).
@nicolasstucki nicolasstucki force-pushed the macro-annotations-fix-splice-owner branch from 8d45fcf to 9431066 Compare December 15, 2022 09:22
@nicolasstucki nicolasstucki merged commit 4b0fe4d into scala:main Dec 19, 2022
@nicolasstucki nicolasstucki deleted the macro-annotations-fix-splice-owner branch December 19, 2022 15:48
nicolasstucki added a commit that referenced this pull request Dec 19, 2022
Enable modification of classes with `MacroAnnotation`:
 * Can annotate `class` to transform it
 * Can annotate `object` to transform the companion class

Supported class modifications:
* Modify the implementations of `def`, `val`, `var`, `lazy val`,
`class`, `object` in the class
* Add new `def`, `val`, `var`, `lazy val`, `class`, `object` members to
the class
* Add a new override for a `def`, `val`, `var`, `lazy val` members in
the class

Restrictions:
* An annotation on a top-level class cannot return a top-level `def`,
`val`, `var`, `lazy val`.


Related PRs:
 * Includes #16513
 * Follows #16392
 * Followed by #16534
@Kordyjan Kordyjan modified the milestones: 3.3.0-RC1, 3.3.0 Aug 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants