Skip to content

Commit c871e49

Browse files
committed
[IDE] Recover from incomplete unowned and nonisolated in isStartOfSwiftDecl
1 parent 951988c commit c871e49

File tree

1 file changed

+49
-27
lines changed

1 file changed

+49
-27
lines changed

lib/Parse/ParseDecl.cpp

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5691,33 +5691,61 @@ bool swift::isKeywordPossibleDeclStart(const LangOptions &options,
56915691
}
56925692

56935693
static bool
5694-
isParenthesizedModifier(Parser &P, StringRef name,
5695-
std::initializer_list<StringRef> allowedArguments) {
5694+
consumeIfParenthesizedModifier(Parser &P, StringRef name,
5695+
std::initializer_list<StringRef> allowedArguments) {
56965696
assert((P.Tok.getText() == name) && P.peekToken().is(tok::l_paren) &&
56975697
"Invariant violated");
56985698

56995699
// Look ahead to parse the parenthesized expression.
5700-
Parser::BacktrackingScope Backtrack(P);
5700+
Parser::CancellableBacktrackingScope backtrack(P);
57015701
P.consumeToken(tok::identifier);
57025702
P.consumeToken(tok::l_paren);
5703+
5704+
const Token &Tok2 = P.peekToken();
5705+
if (P.consumeIf(tok::code_complete)) {
5706+
// If a code complete token is present, recover from missing/incorrect argument and missing '('
5707+
P.consumeIf(tok::identifier);
5708+
P.consumeIf(tok::r_paren);
5709+
backtrack.cancelBacktrack();
5710+
return true;
5711+
}
5712+
5713+
if (P.Tok.is(tok::identifier) && !P.Tok.isContextualDeclKeyword() && Tok2.is(tok::code_complete)) {
5714+
P.consumeToken(tok::identifier);
5715+
P.consumeToken(tok::code_complete);
5716+
5717+
// If a code complete is present with a non-keyword token before it, recover from missing/incorrect argument and missing '('
5718+
if (!P.Tok.isContextualDeclKeyword()) {
5719+
P.consumeIf(tok::identifier);
5720+
}
5721+
P.consumeIf(tok::r_paren);
5722+
backtrack.cancelBacktrack();
5723+
return true;
5724+
}
57035725

57045726
const bool argumentIsAllowed =
57055727
std::find(allowedArguments.begin(), allowedArguments.end(),
57065728
P.Tok.getText()) != allowedArguments.end();
5707-
return argumentIsAllowed && P.Tok.is(tok::identifier) &&
5708-
P.peekToken().is(tok::r_paren);
5729+
5730+
if (argumentIsAllowed && P.Tok.is(tok::identifier) &&
5731+
P.peekToken().is(tok::r_paren)) {
5732+
backtrack.cancelBacktrack();
5733+
return true;
5734+
}
5735+
5736+
return false;
57095737
}
57105738

57115739
/// Given a current token of 'unowned', check to see if it is followed by a
5712-
/// "(safe)" or "(unsafe)" specifier.
5713-
static bool isParenthesizedUnowned(Parser &P) {
5714-
return isParenthesizedModifier(P, "unowned", {"safe", "unsafe"});
5740+
/// "(safe)" or "(unsafe)" specifier and consumes if it is.
5741+
static bool consumeIfParenthesizedUnowned(Parser &P) {
5742+
return consumeIfParenthesizedModifier(P, "unowned", {"safe", "unsafe"});
57155743
}
57165744

57175745
/// Given a current token of 'nonisolated', check to see if it is followed by an
5718-
/// "(unsafe)" specifier.
5719-
static bool isParenthesizedNonisolated(Parser &P) {
5720-
return isParenthesizedModifier(P, "nonisolated", {"unsafe"});
5746+
/// "(unsafe)" specifier and consumes if it is.
5747+
static bool consumeIfParenthesizedNonisolated(Parser &P) {
5748+
return consumeIfParenthesizedModifier(P, "nonisolated", {"unsafe"});
57215749
}
57225750

57235751
static void skipAttribute(Parser &P) {
@@ -5878,27 +5906,21 @@ bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes,
58785906
// If it might be, we do some more digging.
58795907

58805908
// If this is 'unowned', check to see if it is valid.
5881-
if (Tok.getText() == "unowned" && Tok2.is(tok::l_paren) &&
5882-
isParenthesizedUnowned(*this)) {
5909+
if (Tok.getText() == "unowned" && Tok2.is(tok::l_paren)) {
58835910
Parser::BacktrackingScope Backtrack(*this);
5884-
consumeToken(tok::identifier);
5885-
consumeToken(tok::l_paren);
5886-
consumeToken(tok::identifier);
5887-
consumeToken(tok::r_paren);
5888-
return isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false,
5889-
/*hadAttrsOrModifiers=*/true);
5911+
if (consumeIfParenthesizedUnowned(*this)) {
5912+
return isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false,
5913+
/*hadAttrsOrModifiers=*/true);
5914+
}
58905915
}
58915916

58925917
// If this is 'nonisolated', check to see if it is valid.
5893-
if (Tok.isContextualKeyword("nonisolated") && Tok2.is(tok::l_paren) &&
5894-
isParenthesizedNonisolated(*this)) {
5918+
if (Tok.isContextualKeyword("nonisolated") && Tok2.is(tok::l_paren)) {
58955919
BacktrackingScope backtrack(*this);
5896-
consumeToken(tok::identifier);
5897-
consumeToken(tok::l_paren);
5898-
consumeToken(tok::identifier);
5899-
consumeToken(tok::r_paren);
5900-
return isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false,
5901-
/*hadAttrsOrModifiers=*/true);
5920+
if (consumeIfParenthesizedNonisolated(*this)) {
5921+
return isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false,
5922+
/*hadAttrsOrModifiers=*/true);
5923+
}
59025924
}
59035925

59045926
if (Tok.isContextualKeyword("actor")) {

0 commit comments

Comments
 (0)