-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[libSyntax] Create deferred nodes in SyntaxParseActions #36277
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
[libSyntax] Create deferred nodes in SyntaxParseActions #36277
Conversation
5164eb4
to
5f3abe3
Compare
@swift-ci Please smoke test |
/// Returns the opaque data of this node. This must be interpreted by the | ||
/// \c SyntaxParseAction, which likely also needs the node type to know | ||
/// what type of node the data represents. | ||
OpaqueSyntaxNode getData() const { return Data.getOpaque(); } | ||
|
||
RecordedOrDeferredNode getRecordedOrDeferredNode() const { return Data; } |
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.
These methods (getData()
and getRecordedOrDeferredNode()
) breaks the "move-only" semantics of ParsedRawSyntaxNode
. "Data" should not be extracted without resetting the ParsedRawSyntaxNode
.
This is important to ensure not to discard parsed recorded nodes without putting them into the final tree.
Previously, we allowed copying via copyDeferred()
method only if it's deferred.
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.
We need some kind of “get data, but don’t take” method to retrieve the node’s children here.
I’ve renamed the method to getUnsafeOpaqueData
and added a comment that the data returned by it should only be used to inspect the node, not to record it. Are you OK with that?
Also, while looking through the uses of this method, I actually found a case where we should have been using takeData
instead, so good catch.
I modified getRecordedOrDeferredNode
to takeRecordedOrDeferredNode
.
case RecordedOrDeferredNode::Kind::Null: | ||
break; | ||
case RecordedOrDeferredNode::Kind::Recorded: | ||
llvm_unreachable("Children of deferred nodes must also be deferred"); |
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.
Do we have any comments why deferred nodes can't contain recorded nodes? If not, could you add some?
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.
It’s because of the way we create the syntax tree. Once we put the SyntaxParsingContext
in deferred node all (child) nodes are also deferred. If we chose to record child nodes of deferred nodes, we would also get into trouble should we decide to discard the deferred node, because now we’d also need to discard the recorded child node, which cannot be done. Please correct me if any of the assumptions I’m making here are wrong.
We don’t have a comment about this anywhere. I’ve added one here.
0fa3e7e
to
7cca0af
Compare
7cca0af
to
0c136af
Compare
@swift-ci Please smoke test |
…yntaxRecorder This is an intermediate step in the effort to push deferred node handling all the way down to SyntaxParseActions.
By now ParsedRawSyntaxNode does not have any knowledge about deferred node data anymore, which frees up SyntaxParseActions (and, in particular its sublass SyntaxTreeCreator) to perform optimisations to more efficiently create and record deferred nodes.
…e as RecordedOrDeferredNode This is mostly a clean-up commit. ParsedRawSyntaxNode stores an OpaqueSyntaxNode and its DataKind so it might as well use a RecordedOrDeferredNode.
This requires a SyntaxParsingContext to be passed to the dump function and was thus disabled in an earlier commit
…ParsedRawSyntaxNode They are superseded by getData/takeData
0c136af
to
1f695c9
Compare
@swift-ci Please smoke test |
Parsed${child.type_name} Parsed${node.name}::getDeferred${child.name}() { | ||
return Parsed${child.type_name} {getRaw().getDeferredChildren()[${node.name}::Cursor::${child.name}].copyDeferred()}; | ||
Parsed${child.type_name} Parsed${node.name}::getDeferred${child.name}(const SyntaxParsingContext *SyntaxContext) { | ||
return Parsed${child.type_name} {getRaw().getDeferredChild(${node.name}::Cursor::${child.name}, SyntaxContext).copyDeferred()}; |
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.
copyDeferred()
is not needed I believe
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.
Parsed${node.name}::getDeferred${child.name}() { | ||
auto &RawChild = getRaw().getDeferredChildren()[${node.name}::Cursor::${child.name}]; | ||
Parsed${node.name}::getDeferred${child.name}(const SyntaxParsingContext *SyntaxContext) { | ||
auto RawChild = getRaw().getDeferredChild(${node.name}::Cursor::${child.name}, SyntaxContext); | ||
if (RawChild.isNull()) | ||
return None; | ||
return Parsed${child.type_name} {RawChild.copyDeferred()}; |
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.
ditto
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.
If you remove them, copyDeferred()
is not used anymore...
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.
See above.
The getData and getRecordedOrDeferredNode methods broke the move-only semantics of ParsedRawSyntaxNode because it allowed retrieving the data without resetting it. Change most uses to use takeData or takeRecordedOrDeferredNode instead of the get methods. To retrieve the children of a ParsedRawSyntaxNode, we still need a way to access the OpaqueSyntaxNode for inspection by the SyntaxParseActions without resetting it. For this, we still maintain a method with the semantics of getData, but it’s now called getUnsafeOpaqueData to make sure it’s not accidentally used.
1f695c9
to
bf6aff9
Compare
@swift-ci Please smoke test |
@swift-ci Please smoke test Windows |
Move the creation of deferred nodes from the
ParsedRawSyntaxRecorder
toSyntaxParseActions
. By itself this does not offer any advantage, but from here we will be able to optimize the creation of deferred nodes inside the differentSyntaxParseActions
implementations.All implementation that is currently in
SyntaxParseActions
is transitional. In the next PR these will be pushed toCLibParseActions
(which will mostly match what’s currently inSyntaxParseActions
) andSyntaxTreeCreator
(which can avoid creating deferred nodes altogether by directly constructingRawSyntax
nodes).