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

Attached macros #1932

Merged
merged 19 commits into from Feb 16, 2023
Merged

Attached macros #1932

merged 19 commits into from Feb 16, 2023

Conversation

DougGregor
Copy link
Member

No description provided.

* Split peer/member/accessor macro implementations into separate protocols and attribute spellings, so the compiler can query them in a more fine-grained manner.
* Removed function-body macros... for the moment. We'll come back to them.
* Add example showing composition of different macro roles for the same macro to effect property-wrappers behavior.

```swift
/// Create the necessary members to turn a struct into an option set.
@attached(member, names: names(rawValue), arbitrary]) macro optionSetMembers
Copy link
Collaborator

Choose a reason for hiding this comment

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

There's an open square bracket missing here, I believe after names:?

Also, according to the freestanding proposal, should this be expressed as named("rawValue")?

Copy link
Member Author

Choose a reason for hiding this comment

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

Right on both counts, thank you!

@attached(peer, names: overloaded) macro addCompletionHandler()
```

This macro uses the `@attached` attribute to indicate that it is an attached peer attribute. The `names` argument specifies that how the names of the peer declarations are created, using an extended form of the scheme introduced with [freestanding macros](https://github.com/DougGregor/swift-evolution/blob/freestanding-macros/proposals/nnnn-freestanding-macros.md#up-front-declarations-of-newly-introduced-names). In this case, `overloaded` means that this macro will produce a peer that is overloaded with the declaration to which it is attached, i.e., it has the same base name.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Here and elsewhere, if we start this review before freestanding macros, I wonder if we should move the linked content for the naming scheme into a section of this proposal. Alternatively, it could go into the vision and both proposals could link to it?

Copy link
Member Author

Choose a reason for hiding this comment

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

I've pulled in all of the linked content so this proposal is... freestanding. Also, added more detail

@attached(peer, names: overloaded) macro addCompletionHandler()
```

This macro uses the `@attached` attribute to indicate that it is an attached peer attribute. The `names` argument specifies that how the names of the peer declarations are created, using an extended form of the scheme introduced with [freestanding macros](https://github.com/DougGregor/swift-evolution/blob/freestanding-macros/proposals/nnnn-freestanding-macros.md#up-front-declarations-of-newly-introduced-names). In this case, `overloaded` means that this macro will produce a peer that is overloaded with the declaration to which it is attached, i.e., it has the same base name.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since functions can be distinguished by their full decl name with argument labels, what is the significance of telling the compiler that the peer declaration has the same base name? Can you expand on what the compiler does with this information?

Copy link
Member Author

Choose a reason for hiding this comment

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

The compiler tends to ignore the labels when it does name lookup. I've added some more text about how this information is used.


The implementation of the `dictionaryStorage` macro would create the accessor declarations shown above, using either the `key` argument (if present) or deriving the key name from the property name. The effect of this macro isn't something that can be done with a property wrapper, because the property wrapper wouldn't have access to `self.storage`.

The presence of an accessor macro on a stored property removes the initializer. It's up to the implementation of the accessor macro to either diagnose the presence of the initializer (if it cannot be used) or incorporate it in the result.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this could use a little more clarity (maybe an example). Are you saying that if someone writes the following:

@dictionaryStorage
var name: String = "defaultName"

Then the compiler will "prune" the = "defaultName" and it's entirely up to the macro to fetch it from the syntax tree and decide how they want to use it?

If so, would this prevent macros that only want to attach willSet/didSet accessors, since the macro's return value is an array of AccessorDecls and thus there would be no place to reattach the initializer clause?

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, good catch. This was a hole in the design; I've updated the proposal to address this.

As with freestanding macros, attached declaration macros are declared with `macro`, and have [type-checked macro arguments](https://github.com/apple/swift-evolution/blob/main/proposals/0382-expression-macros.md#type-checked-macro-arguments-and-results) that allow their behavior to be customized. Attached macros are identified with the `@attached` attribute, which also provides the specific role as well as [any names they introduce](https://github.com/DougGregor/swift-evolution/blob/freestanding-macros/proposals/nnnn-freestanding-macros.md#up-front-declarations-of-newly-introduced-names). For example, the aforemented macro emulating property wrappers could be declared as follows:

```swift
@attached(peer, names: prefixed(_))
Copy link
Collaborator

Choose a reason for hiding this comment

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

In other parts of the proposal, the syntax used here involves a string literal: prefixed("_"). Can you update these so that they're consistent throughout (whichever one happens to be correct)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, thank you!

Copy link
Collaborator

@allevato allevato left a comment

Choose a reason for hiding this comment

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

Thanks! I'm going to start the review momentarily.

@allevato allevato merged commit 2c5fc1c into apple:main Feb 16, 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
2 participants