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

Add the ability to create VariableDeclSyntax instances with multiple accessors using a result builder #2948

Open
thafner0 opened this issue Jan 21, 2025 · 2 comments

Comments

@thafner0
Copy link

thafner0 commented Jan 21, 2025

Creating VariableDeclSyntax instances using a result builder is super helpful to generate readable yet flexible code. This functionality works fine if generating a single get accessor using the abbreviated syntax (simple closure with statements being used in the getter). However, if it is necessary to have multiple accessors, this requires much more messy code since result builders don't support multiple accessors at this time. It would be ideal to have a second result builder initializer that accepted a closure returning a AccessorDeclListSyntax using an AccessorDeclListBuilder to construct the list of accessors. The two initializers could use a shared private initializer that would be responsible for doing all common work done in both with the two precise implementations merely handling the difference in AccessorDeclSyntax.Accessors case.

Comparison Between Current and Proposed Implmentations

The proposed implementation is only adding to what is already present and would be added into the SwiftSyntaxBuilder target. The below code snippets assume that SwiftSyntax and SwiftSyntaxBuilder are both imported.

Current Implementation

To generate the code below:

var example: Int {
get {
// code in getter
}
set {
// code in setter
}
}

The current implementation would require the code below:

VariableDeclSyntax(
bindingSpecifier: .keyword(.var, trailingTrivia: .space),
bindingsBuilder: PatternBindingListSyntax {
PatternBindingSyntax(
pattern: PatternSyntax("example"),
typeAnnotation: TypeAnnotationSyntax(
colon: .colonToken(trailingTrivia: .space),
type: TypeSyntax("Int")
),
accessorBlock: .accessors(AccessorDeclListSyntax {
try! AccessorDeclSyntax("get") {
// getter code represented as SwiftSyntax types
}
try! AccessorDeclSyntax("set") {
// setter code represented as SwiftSyntax types
}
})
}
)

The code immediately above could be simplified under the proposed changes as shown below (providing there is only one binding, which is a similar requirement to the existing implementation of result builders for getter-only accessors):

VariableDeclSyntax("var example: Int") {
try! AccessorDeclSyntax("get") {
// getter code represented as SwiftSyntax types
}
try! AccessorDeclSyntax("set") {
// setter code represented as SwiftSyntax types
}
}
@ahoppen
Copy link
Member

ahoppen commented Jan 21, 2025

Synced to Apple’s issue tracker as rdar://143339412

@thafner0
Copy link
Author

Hmmm, I'm a little intrigued by something I just found whilst playing around a little bit. I noticed in the tests while I was adding the first version of the implementation for this to my own fork that the CodeBlockItemListBuilder accepts AccessorDeclSyntax instances within it and it validates successfully (when run from VariableDeclSyntax). I also tried running it in a test and having a dummy macro expand code using the getter result builder implementation for VariableDeclSyntax to pass in a getter and a setter. Neither the assertMacroExpansion test function nor the compiler itself complained about me using this in a way that seems slightly inconsistent with how it's intended. Is this a bug? In other words, should that result builder not accept AccessorDeclSyntax instances with it? I had initially thought that AccessorDeclSyntax instances wouldn't be accepted by the result builder in this way since it doesn't really make sense to have a random accessor block within a general code block which would allow overloading to easily add the functionality described in this issue.

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

No branches or pull requests

2 participants