@@ -5691,33 +5691,61 @@ bool swift::isKeywordPossibleDeclStart(const LangOptions &options,
5691
5691
}
5692
5692
5693
5693
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) {
5696
5696
assert ((P.Tok .getText () == name) && P.peekToken ().is (tok::l_paren) &&
5697
5697
" Invariant violated" );
5698
5698
5699
5699
// Look ahead to parse the parenthesized expression.
5700
- Parser::BacktrackingScope Backtrack (P);
5700
+ Parser::CancellableBacktrackingScope backtrack (P);
5701
5701
P.consumeToken (tok::identifier);
5702
5702
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
+ }
5703
5725
5704
5726
const bool argumentIsAllowed =
5705
5727
std::find (allowedArguments.begin (), allowedArguments.end (),
5706
5728
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 ;
5709
5737
}
5710
5738
5711
5739
// / 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" });
5715
5743
}
5716
5744
5717
5745
// / 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" });
5721
5749
}
5722
5750
5723
5751
static void skipAttribute (Parser &P) {
@@ -5878,27 +5906,21 @@ bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes,
5878
5906
// If it might be, we do some more digging.
5879
5907
5880
5908
// 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)) {
5883
5910
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
+ }
5890
5915
}
5891
5916
5892
5917
// 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)) {
5895
5919
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
+ }
5902
5924
}
5903
5925
5904
5926
if (Tok.isContextualKeyword (" actor" )) {
0 commit comments