-
Notifications
You must be signed in to change notification settings - Fork 465
Add methods from RangeReplaceableCollection to SyntaxCollection and remove add* methods on syntax nodes that have a collection as child
#1958
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 |
With swiftlang/swift-syntax#1958, `node.filter` will return a new `SyntaxCollection` that has the filtered elements removed (instead of the array it’s currently returning). Since that node has elements removed, it will have a new parent and thus all the nodes inside of it have new IDs. Use `where` after `for` to get the elements with the same IDs and just don’t iterate the elements that don’t satisfy the condition. This is also more performant because it doesn’t create an intermediate array.
|
@swift-ci Please test |
4635597 to
b690ece
Compare
|
@swift-ci Please test |
|
@swift-ci Please test Windows |
With swiftlang/swift-syntax#1958, `node.filter` will return a new `SyntaxCollection` that has the filtered elements removed (instead of the array it’s currently returning). Since that node has elements removed, it will have a new parent and thus all the nodes inside of it have new IDs. Use `where` after `for` to get the elements with the same IDs and just don’t iterate the elements that don’t satisfy the condition. This is also more performant because it doesn’t create an intermediate array.
b690ece to
d069a9f
Compare
|
@swift-ci Please test |
|
@swift-ci Please test Windows |
bnbarham
left a comment
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.
My main concern here is that many of the methods list a Big O that isn't true for our implementation. Eg. even something like append ends up doing much more work than you'd otherwise expect (since it is constructing all parents + has to copy the elements into a new raw syntax node).
That's what all the add* are doing today though, so while I don't think this is blocking, perhaps we should add some extra documentation in. There's also the filter case, which we should probably make a custom implementation for.
| self.init(Syntax(data))! | ||
| } | ||
|
|
||
| /// Create an empty ``SyntaCollection`` with no children. |
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.
| /// Create an empty ``SyntaCollection`` with no children. | |
| /// Create an empty ``SyntaxCollection`` with no children. |
d069a9f to
fc54536
Compare
|
I added an overload of |
|
@swift-ci Please test |
|
|
||
| /// Create an empty ``SyntaxCollection`` with no children. | ||
| public init() { | ||
| self.init([]) |
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 guess this is the other downside of using RangeReplaceableCollection. This constructor should really never be used and makes it super easy to drop the parent accidentally.
|
@swift-ci Please test Windows |
fc54536 to
e07c1bf
Compare
RangeReplaceableCollection and remove add* methods on syntax nodes that have a collection as childRangeReplaceableCollection to SyntaxCollection and remove add* methods on syntax nodes that have a collection as child
e07c1bf to
c827d90
Compare
|
@swift-ci Please test |
| let addedElements: ArrayElementListSyntax = Array([integerLiteralElement(4)]) + array.elements | ||
| XCTAssertEqual(addedElements.count, 4) | ||
| // If the first collection of + doesn’t have a parent, it doesn’t really | ||
| // make sense to inherit the parent from the second collection. | ||
| XCTAssert(addedElements.parent?.is(ArrayExprSyntax.self) ?? false) |
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 wouldn't expect this. This is basically prepending and I think I'd want to keep the parent in that case?
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.
testPrependingElement tests this case FWIW
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.
But that’s what it’s testing. after adding the elements, the parent should still be an ArrayExprSyntax. Or am I misunderstanding you?
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.
That's... true 🤔 The comment seems to be suggesting the opposite doesn't it? And then I read the assert as an XCTAssertFalse.
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.
Oh, the comment was outdated…
| // If the first collection of + doesn’t have a parent, it doesn’t really | ||
| // make sense to inherit the parent from the second collection. | ||
| XCTAssert(addedElements.parent?.is(ArrayExprSyntax.self) ?? false) | ||
| } |
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.
Would be good to test the added functions too (append, insert, replace). Or update the existing ones - they all manipulate the underlying list for the most part.
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.
Added tests
Especially the `+` operators make manipulation of `SyntaxCollection` a lot easier. `SyntaxCollection` doesn’t conform to `RangeReplaceableCollection` because of two reasons: - `RangeReplaceableCollection` assumes that creating a new colleciton and adding all elements from another collection to it results in the same collection. This is not true for `SyntaxCollection` because the new collection wouldn’t have a parent. This causes eg. the default implementation of `filter` to misbehave. - It can’t make the complexity guarantees that `RangeReplaceableCollection` requires, e.g. `append` is `O(tree depth)` instead of `O(1)`. For the same reason, also remove the conformance to `MutableCollection`.
c827d90 to
744275d
Compare
|
@swift-ci Please test |
|
@swift-ci Please test Windows |
| XCTAssertNotNil(newArrayElementList.child(at: 1)) | ||
| XCTAssert(!newArrayElementList.child(at: 1)!.kind.isSyntaxCollection) | ||
| XCTAssertEqual("\(newArrayElementList.child(at: 1)!)", "1") | ||
| fileprivate func assertSyntaxCollectionManipulation( |
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.
Would it be worth adding a parent in here and then checking we still have a parent in the transformed? Or are there cases where that's not always true?
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.
That’s why I am performing all the transformations on an ArrayExprSyntax instead of the actual collection type ArrayElementListSyntax. That way the substructure test checks that we still have the collection anchored in a parent.
With swiftlang/swift-syntax#1958, `node.filter` will return a new `SyntaxCollection` that has the filtered elements removed (instead of the array it’s currently returning). Since that node has elements removed, it will have a new parent and thus all the nodes inside of it have new IDs. Use `where` after `for` to get the elements with the same IDs and just don’t iterate the elements that don’t satisfy the condition. This is also more performant because it doesn’t create an intermediate array.
Especially the
+operators make manipulation ofSyntaxCollectiona lot easier.SyntaxCollectiondoesn’t conform toRangeReplaceableCollectionbecause of two reasons:RangeReplaceableCollectionassumes that creating a new colleciton and adding all elements from another collection to it results in the same collection. This is not true forSyntaxCollectionbecause the new collection wouldn’t have a parent. This causes eg. the default implementation offilterto misbehave.RangeReplaceableCollectionrequires, e.g.appendisO(tree depth)instead ofO(1).For the same reason, also remove the conformance to
MutableCollection.With those operators and methods, we no longer need the
add*methods on syntax nodes that have a syntax collection as their child.