-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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
ASTGen: An assortment of strides and improvements #67111
Conversation
// RUN: %empty-directory(%t) | ||
// RUN: %target-swift-frontend %s -dump-parse -disable-availability-checking -enable-experimental-feature ParserASTGen > %t/astgen.ast | ||
// RUN: %target-swift-frontend %s -dump-parse -disable-availability-checking > %t/cpp-parser.ast | ||
// RUN: %diff -u %t/astgen.ast %t/cpp-parser.ast |
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.
This is of course ersatz diffing — we ought to implement an AST matcher.
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 should, but it's a big task and the approach you're using here can provide real value along the way.
Nice! |
@swift-ci please smoke test |
5f8c4e2
to
fbc1f14
Compare
This comment was marked as duplicate.
This comment was marked as duplicate.
fbc1f14
to
a491701
Compare
This comment was marked as duplicate.
This comment was marked as duplicate.
a491701
to
332b8a6
Compare
@swift-ci please smoke test macOS |
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.
Thanks @AnthonyLatsis. Big fan of your operator test choices :)
|
||
// REQUIRES: executable_test | ||
|
||
// -enable-experimental-feature requires an asserts build | ||
// REQUIRES: asserts | ||
|
||
func test1(x: Int, fn: (Int) -> Int) -> Int { | ||
let xx = fn(42) | ||
// NB: Ridiculous formatting to test that we do not include leading trivia in locations. |
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.
Could use inline comments instead , I'm not sure which is more readable though to be honest.
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.
This is really quite awesome! A few minor comments here and there, but I love that you've increased the coverage of ASTGen so far.
It would be fun to follow this up with the infrastructure to redirect the C++ parser over to ASTGen for specific declaration kinds (e.g., import decls, operators, other small stuff), like I did in #66033, which lets you run a whole bunch of code through a narrow slice of ASTGen.
case .keyword(.none): self = .none | ||
case .keyword(.left): self = .left | ||
case .keyword(.right): self = .right | ||
default: fatalError("Unknown precedence group associativity value") |
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.
Should this produce a diagnostic rather than failing? The incoming syntax tree could be ill-formed.
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 not expect a SwiftParserDiagnostics
pass to catch this sort of thing? Why do we want to allow for translation of ill-formed syntax trees?
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.
ASTGen should handle any swift-syntax tree, whether from the parser or not. There's a few cases that currently have !
that really should not as well. @ahoppen as I know he has strong opinions on this :)
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 see, so what we want is to simply emit a generic error about the syntax tree being invalid, I suppose? We don’t seem to currently have a way to bail out without constructing a node either.
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.
ASTGen should handle any swift-syntax tree, whether from the parser or not. There's a few cases that currently have ! that really should not as well.
Does SwiftSyntax have a way to verify nodes? We could have an interceptor or verifier pre-pass rather than having to recover from every corner where the model is too permissive in the middle of translation.
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.
Edit: I just thought about this a little bit more and it’s hard to model the groupAttributes
with an optional child for each of the attribute kinds because we don’t enforce an order of the group attributes. I.e. we need to be able to represent both
precedencegroup T {
assignment: true
higherThan: AdditionPrecedence
}
and
precedencegroup T {
higherThan: AdditionPrecedence
assignment: true
}
And that basically requires a SyntaxCollection
, unfortunately.
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, right. How ugly would it be to not actually enforce their order in the layout? Say, the initializer always inserts the attributes per the parameter order, but one could pass nil
s in the initializer and then insert the attributes in the appropriate order via the setters if necessary. The getters and setters would then work with a specific subrange of the layout of size 4 which is nilled out by default.
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’m not entirely sure what you mean. Do you have a short example of how you think the API should look like?
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.
An optional child for each attribute kind as originally suggested, with accessors similar to these:
public var higherThanRelation: PrecedenceGroupRelationSyntax? {
get {
for index in 11...14 {
guard let childData = data.child(at: index) else {
// No data for this attribute (attributes are stored contiguously, i.e., no 'nil' data in between attributes).
break
}
if let value = PrecedenceGroupRelationSyntax(Syntax(childData)) {
return value
}
}
return nil
}
set(value) {
for index in 11...14 {
guard let rawChild = data.rawChild(at: index) else {
// No data for this attribute (attributes are stored contiguously, i.e., no 'nil' data in between attributes).
// Stick it in at this index.
self = PrecedenceGroupDeclSyntax(data.replacingChild(at: index, with: value?.data, arena: SyntaxArena()))
return
}
if rawChild.kind == .precedenceGroupRelation {
if let value {
// Simply replace the data at this index.
self = PrecedenceGroupDeclSyntax(data.replacingChild(at: index, with: value.data, arena: SyntaxArena()))
return
} else {
self = PrecedenceGroupDeclSyntax(data.replacingChild(at: index, with: nil, andShiftingItTo: 14, arena: SyntaxArena()))
}
}
}
}
}
}
Another possibility is to statically feature the 4 optional child attributes in PrecedenceGroupAttributeListSyntax
, as they would have been in PredenceGroupDeclSyntax
, perhaps retaining the conformance to SyntaxCollection
. This way no changes to PredenceGroupDeclSyntax
are necessary.
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.
An optional child for each attribute kind as originally suggested, with accessors similar to these.
The issue I see with this design is that a client of SwiftSyntax might create a PrecedenceGroupDeclSyntax
that has two higherThan
relations in the groupAttributes
and the higherThanRelation
getter would only return the first.
Similarly, if you set a higherThan
relation using this setter, you can’t control where it is being inserted if no higherThan
relation exists yet. So
let pg = PrecedenceGroupDeclSyntax()
pg.higherThanRelation = // …
pg.assignment = // ...
would give you a different node than
let pg = PrecedenceGroupDeclSyntax()
pg.assignment = // ...
pg.higherThanRelation = // …
and that’s quite surprising IMO.
func visit(_ node: PrecedenceGroupDeclSyntax) -> ASTNode { | ||
let (name, nameLoc) = self.bridgedIdentifierAndSourceLoc(for: node.identifier) | ||
|
||
struct PrecedenceGroupBody { |
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.
For precedence groups and operators, I wonder if we should instead build on top of the SwiftOperators
library, which has a mapping from the syntax tree into a more semantic representation (Operator
and PrecedenceGroup
).
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.
Apparently the inits from SwiftOperators
assume the nodes are valid, so we would have to do most of the same work in ASTGen
to prevalidate the nodes and diagnose issues before calling these inits, like switching on the fixity of an operator or iterating over the attributes of a precedence group. Do you believe there is something to gain from building on top of SwiftOperators
regardless?
Just a quick comment: I’d like to review the PR but won’t get to it until Monday/Tuesday. I’d appreciate if you could leave it open until then. |
No problem! I would hate to land this without a review from 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.
Here’s my first round of review. You’re getting a bit of my complaints with the current ASTGen design but I think that I managed to keep my comments somewhat focused so that I don’t require you to do a massive refactoring first.
Name: name, | ||
NameLoc: nameLoc, | ||
SecondName: secondName, | ||
SecondNameLoc: secondNameLoc, | ||
UnderscoreLoc: nil, /*N.B. Only important for SIL*/ | ||
ColonLoc: self.bridgedSourceLoc(for: element.colon), | ||
Type: type, | ||
TrailingCommaLoc: self.bridgedSourceLoc(for: element.trailingComma) |
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.
Just me complaining, no action necessary for you in this PR: I know that you didn’t introduce BridgedTupleTypeElement
but the members of it should really be lowercase so I don’t need to look at uppercase parameter labels in Swift.
b0741a2
to
942f06c
Compare
@swift-ci please smoke test macOS |
953a476
to
448712a
Compare
@swift-ci please smoke test |
@swift-ci Please test Windows |
@ahoppen We have a problem with |
448712a
to
ae83632
Compare
@swift-ci please test Windows |
I take it the conditional def works because we skip the early swift-syntax on Windows. Is this an OK workaround? |
That's not going to be true very soon, but regardless the conditional def seems fine to me - it isn't needed when compiling C++, only when importing into Swift (in which case, it will be defined). Unless I'm misunderstanding something crucial here? |
@swift-ci Please test |
Nah, actually, thank you, I had a brain fart. I just realized the importer invokes clang to parse headers (so of course the attribute will be defined when importing into Swift). For some reason I had this silly impression that it would be reading a normalized MSVC AST on Windows by default, even though I knew the importer reads clang ASTs 🙃 |
@ahoppen @DougGregor @bnbarham @hamishknight Thank you so much for weighing in! |
Woo, it's in! Thanks for all the work here @AnthonyLatsis! |
Thank you for doing all this work! 🙏🏽 |
This pull request focuses on declaration translation, extrapolating preparatory work to the rest of the module for consistency and testing.