-
Notifications
You must be signed in to change notification settings - Fork 10.6k
[SE-0491] Parse and ASTGen module selectors #84362
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
base: main
Are you sure you want to change the base?
Conversation
Try to avoid calling `getSourceRange()` on a decl where that will form an invalid range.
When closing paren is missing, point at the location where it should be found, not the opening paren.
A PatternBindingEntry formed from a MissingPatternSyntax has no valid SourceLocs in it, and a PatternBindingDecl containing only PatternBindingEntries with no valid SourceLocs trips an assertion during availability checking. (Generating dummy SourceLocs can cause invalid overlaps between AvailabilityScopes, so that’s not a workable solution.) The fix is to: • Refuse to generate a PatternBindingEntry from a PatternBindingSyntax with a MissingPatternSyntax (MissingPatternSyntaxes at nested positions don’t have this problem) • Refuse to generate a PatternBindingDecl with no PatternBindingEntries This ensures that the invalid AST nodes are never formed. No current test cases hit this problem, but certain invalid module selector tests can run into this situation when run with ASTGen.
@swift-ci smoke test |
@inline(__always) | ||
func generateSourceLoc(_ node: some SyntaxProtocol) -> SourceLoc { | ||
SourceLoc(at: node.positionAfterSkippingLeadingTrivia, in: self.base) | ||
precondition(node.positionAfterSkippingLeadingTrivia.utf8Offset < 0x0000000100000000) |
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.
What is this for?
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 think this was something I added to chase down a bug caused by missing tokens having very large, invalid offsets that turned into out-of-bounds SourceLoc
s. It probably doesn't belong in this PR; the constant here is a fairly arbitrary "big enough" value.
arguments: ( | ||
leftParen: TokenSyntax, | ||
labels: some Collection<TokenSyntax>, | ||
rightParen: TokenSyntax | ||
)? = Optional<(leftParen: TokenSyntax, labels: [TokenSyntax], rightParen: TokenSyntax)>.none |
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.
Can't this be just DeclNameArgumentsSyntax
?
arguments: ( | |
leftParen: TokenSyntax, | |
labels: some Collection<TokenSyntax>, | |
rightParen: TokenSyntax | |
)? = Optional<(leftParen: TokenSyntax, labels: [TokenSyntax], rightParen: TokenSyntax)>.none | |
arguments: DeclNameArgumentsSyntax? = nil |
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.
Looks like it can be. Good catch!
// The availability checker requires declarations to have valid SourceLocs, but MissingPatternSyntax lowers to | ||
// an implicit AnyPattern with invalid SourceLocs. A top-level MissingPatternSyntax could therefore cause us to | ||
// construct an invalid AST. Drop the whole binding instead. | ||
// No need to diagnose; SwiftParser should have already diagnosed the `MissingPatternSyntax`. |
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 a little unfortunate that we're missing possible diagnostics for the initializer expressions.
Can't we set the SourceLoc if the generated pattern
is AnyPattern with invalid SourceLocs?
(Not sure MissingPatternSyntax
+ non-nil initializer
is possible in practice. 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.
If we rejiggered some things in the bridging layer, I suppose we could create an implicit AnyPattern
with an explicit SourceLoc
. Where would we get that SourceLoc
from, though? The MissingPatternSyntax
won't give us a usable one.
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.
generateSourceLoc(pattern)
would return the location of the next token of var
/let
or ,
. I assume that is not usable because it would overwrap with the next decl? If so, generateSourceLoc(pattern.previousToken(viewMode: .sourceAccurate))
might work, but I'm fine with leaving this as-is for now.
diagnose(Tok, diag::replace_module_selector_with_member_lookup) | ||
.fixItReplace(Tok.getLoc(), "."); | ||
} | ||
HasNext = consumeIf(tok::period) || consumeIf(tok::colon_colon); |
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 you align the implementation with SwiftParser
?
DeclNameRef nameRef = | ||
parseDeclNameRef(nameLoc, diag::impossible_parse, | ||
DeclNameFlag::AllowAnonymousParamNames | | ||
DeclNameFlag::ModuleSelectorUnsupported); |
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.
Is this needed? I believe this is only called when Tok
is tok::dollarident
so there's no chance to have a module selector here.
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, I could roll this back. It was more important back when parseDeclNameRef()
always parsed a module selector and just diagnosed it when you passed ModuleSelectorUnsupported
.
if (P.Tok.is(tok::identifier) && P.peekToken().is(tok::colon_colon)) { | ||
return P.lookahead(2, [&](auto &scope) { |
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 about making isAtModuleSelector()
returning number of module selector tokens and
if (P.Tok.is(tok::identifier) && P.peekToken().is(tok::colon_colon)) { | |
return P.lookahead(2, [&](auto &scope) { | |
if (auto numTokens = P.isAtModuleSelector()) { | |
return P.lookahead(*numTokens, [&](auto &scope) { |
// the same as those of the result node, plus any junk consumed | ||
// afterwards | ||
auto Brace = BraceStmt::create(Context, Result.getStartLoc(), | ||
auto Brace = BraceStmt::create(Context, StartLoc, |
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.
Any reason for this change?
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.
IIRC, there are (invalid code) situations where Result.getStartLoc()
will be an invalid SourceLoc
. When BraceStmt::create
is passed an invalid left brace location and a valid right brace location, calling Stmt::getSourceRange()
will trip an assertion. Using StartLoc
here fixes the issue because, like PreviousLoc
, it is always valid.
break; | ||
case tok::kw_protocol: | ||
if (startsWithLess(peekToken())) { | ||
if (Tok.is(tok::kw_protocol) && startsWithLess(peekToken())) { |
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 don't think this is needed.
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're right; I think it was briefly needed until I factored out diagnoseAndRecover()
into a helper lambda.
This PR adds support for module selectors to the legacy parser and also updates ASTGen to lower the module selector-related syntax nodes introduced by swiftlang/swift-syntax#3091. Although the compiler parses module selectors with this PR, they don't have any actual effect on name lookup or other compiler behavior.
Makes progress on rdar://problem/19481048. Extracted from #34556. Currently under review as SE-0491.