-
Notifications
You must be signed in to change notification settings - Fork 440
Remove the with<childName> functions on syntax nodes #1253
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
Conversation
@swift-ci Please test |
@@ -71,7 +71,7 @@ extension SyntaxProtocol { | |||
/// diagnostic message), return that. | |||
/// Otherwise, return a generic message that describes the tokens in this node. | |||
var shortSingleLineContentDescription: String { | |||
let contentWithoutTrivia = self.withoutLeadingTrivia().withoutTrailingTrivia().description | |||
let contentWithoutTrivia = self.with(\.leadingTrivia, []).with(\.trailingTrivia, []).description |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it would be worth having a description without trivia, seems wasteful to create a new node (twice) just to remove trivia for printing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it seems wasteful but it seems like a fairly narrow use-case and I don’t want to blow up our API surface for such use cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't seem that narrow. Can leave for now, we can always add later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drive-by comment: it's useful for SwiftLint, we currently have 13 occurrences of withoutTrivia().description
https://github.com/search?q=repo%3Arealm%2FSwiftLint%20withoutTrivia().description&type=code
Maybe there's a better way to accomplish this, but that's what we're doing now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, you convinced me. I added trimmedDescription
. I decided against naming it descriptionWithoutTrivia
because that sounds like we would also remove trivia in the middle of the node.
self = with${child.name}(value) | ||
let arena = SyntaxArena() | ||
% if child.is_optional: | ||
let raw = value?.raw | ||
% else: | ||
let raw = value.raw | ||
% end | ||
let newData = data.replacingChild(at: ${idx}, with: raw, arena: arena) | ||
self = ${node.name}(newData) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I was hoping we could use SyntaxNodeStructure
and the need for this entirely. We don't currently have the reverse mapping (ie. keypath -> index), but maybe that would be useful. That would be even more codegen though, not less 😅.
EDIT: We will need that mapping when we eventually make this variadic + want to set multiple in with(...)
at once though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would you want to get rid of these using SyntaxNodeStructure
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can't right, we need the reverse mapping (key path -> index).
@_disfavoredOverload | ||
func with<T>(_ keyPath: WritableKeyPath<\(raw: trait.traitName)Syntax, T>, _ newChild: T) -> \(raw: trait.traitName)Syntax { | ||
var copy: \(raw: trait.traitName)Syntax = self | ||
copy[keyPath: keyPath] = newChild |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
layoutKeyPath
or something instead? keyPath: keyPath
just looks weird 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it’s not just layouts right. keyPath
can also point to trivia.
I know we decided to do extension FunctionDeclSyntax {
enum Cursor {
case attributes(AttributeListSyntax)
case modifiers(ModifierListSyntax?)
...
}
func with(_ values: Cursor...) -> Self {
...
for cursor in values {
switch cursor {
case .attributes(let val): layout[0] = val.raw
case .modifiers(let val): layout[1] = val?.raw
...
}
}
...
}
} So you can call |
A concern accepting KeyPaths on newFn = fn.with(\.self, otherFn) It works, but not sure we should accept this. Also do we want to accept multi-level paths? |
That would just be trading some code generation for another. What I like about the key path approach is that it doesn’t require code generation.
I actually really liked how the with function generalized from layouts to trivia as well. And it’s really just a shorthand to write three lines in one, so I’m totally happy if it generalizes to multi-level key paths. And I don’t see any problem with |
0c105f1
to
a63faeb
Compare
1 similar comment
a63faeb
to
1342762
Compare
Instead, provide a single `with` function that takes a key path of the child you want to replace. This significatnly reduces the amout of code that is being generated for SwiftSyntax. While at it, also remove the `without(Leading|Trailing)?Trivia` functions
1342762
to
1940941
Compare
Instead, provide a single
with
function that takes a key path of the child you want to replace. This significatnly reduces the amout of code that is being generated for SwiftSyntax.While at it, also remove the
without(Leading|Trailing)?Trivia
functions.@DougGregor I changed a few calls of
token.withoutTrivia()
in macros totoken.text
, which should perform the same thing while also being slightly more efficient.