@@ -665,8 +665,6 @@ bool Parser::parseSpecializeAttributeArguments(
665
665
}
666
666
if (ParamLabel == " target" ) {
667
667
if (!parseSILTargetName (*this )) {
668
- SyntaxParsingContext ContentContext (SyntaxContext,
669
- SyntaxKind::DeclName);
670
668
DeclNameLoc loc;
671
669
targetFunction = parseDeclNameRef (
672
670
loc, diag::attr_specialize_expected_function,
@@ -2482,17 +2480,13 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
2482
2480
return false ;
2483
2481
}
2484
2482
consumeToken (tok::colon);
2485
- {
2486
- SyntaxParsingContext ContentContext (SyntaxContext,
2487
- SyntaxKind::DeclName);
2488
-
2489
- DeclNameLoc loc;
2490
- replacedFunction = parseDeclNameRef (loc,
2491
- diag::attr_dynamic_replacement_expected_function,
2492
- DeclNameFlag::AllowZeroArgCompoundNames |
2493
- DeclNameFlag::AllowKeywordsUsingSpecialNames |
2494
- DeclNameFlag::AllowOperators);
2495
- }
2483
+
2484
+ DeclNameLoc loc;
2485
+ replacedFunction = parseDeclNameRef (loc,
2486
+ diag::attr_dynamic_replacement_expected_function,
2487
+ DeclNameFlag::AllowZeroArgCompoundNames |
2488
+ DeclNameFlag::AllowKeywordsUsingSpecialNames |
2489
+ DeclNameFlag::AllowOperators);
2496
2490
}
2497
2491
2498
2492
// Parse the matching ')'.
@@ -8104,6 +8098,42 @@ Parser::parseDeclOperator(ParseDeclOptions Flags, DeclAttributes &Attributes) {
8104
8098
return DCC.fixupParserResult (Result);
8105
8099
}
8106
8100
8101
+ template <typename Fn>
8102
+ static ParserStatus
8103
+ parsePrecedenceGroupNameList (Parser &P, Fn takeGroupName) {
8104
+ SourceLoc prevCommaLoc;
8105
+ do {
8106
+ SyntaxParsingContext NameCtxt (P.SyntaxContext ,
8107
+ SyntaxKind::PrecedenceGroupNameElement);
8108
+ if (P.Tok .is (tok::code_complete)) {
8109
+ if (P.CodeCompletion )
8110
+ // FIXME: weird that we use PrecedenceGroupRelation, not NameElement.
8111
+ P.CodeCompletion ->
8112
+ completeInPrecedenceGroup (SyntaxKind::PrecedenceGroupRelation);
8113
+ P.consumeToken ();
8114
+ return makeParserCodeCompletionStatus ();
8115
+ }
8116
+
8117
+ DeclNameLoc nameLoc;
8118
+ auto name = P.parseDeclNameRef (nameLoc,
8119
+ diag::expected_group_name_in_precedencegroup_list, {});
8120
+ if (!name)
8121
+ return makeParserError ();
8122
+
8123
+ takeGroupName (prevCommaLoc, name, nameLoc);
8124
+
8125
+ if (P.Tok .is (tok::code_complete)
8126
+ && P.getEndOfPreviousLoc () == P.Tok .getLoc ()) {
8127
+ P.consumeToken ();
8128
+ return makeParserCodeCompletionStatus ();
8129
+ }
8130
+ if (!P.consumeIf (tok::comma, prevCommaLoc))
8131
+ break ;
8132
+ } while (true );
8133
+ P.SyntaxContext ->collectNodesInPlace (SyntaxKind::PrecedenceGroupNameList);
8134
+ return makeParserSuccess ();
8135
+ }
8136
+
8107
8137
ParserResult<OperatorDecl>
8108
8138
Parser::parseDeclOperatorImpl (SourceLoc OperatorLoc, Identifier Name,
8109
8139
SourceLoc NameLoc, DeclAttributes &Attributes) {
@@ -8131,56 +8161,58 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name,
8131
8161
return makeParserCodeCompletionResult<OperatorDecl>();
8132
8162
}
8133
8163
8134
- SyntaxParsingContext ListCtxt (SyntaxContext, SyntaxKind::IdentifierList);
8135
-
8136
- (void )parseIdentifier (groupName, groupLoc,
8137
- diag::operator_decl_expected_precedencegroup,
8138
- /* diagnoseDollarPrefix=*/ false );
8164
+ // Although we parse this as a list, we actually only want there to be zero
8165
+ // (prefix/postfix) or one (infix) elements. These SourceLocs point to the
8166
+ // ends of the elements that should not be there (including the introducer
8167
+ // token for the first one) so that we can diagnose them all at once. If
8168
+ // `typesEndLoc` never becomes valid, we didn't find any excess elements.
8169
+ SourceLoc excessStartLoc = isInfix ? SourceLoc () : colonLoc;
8170
+ SourceLoc excessEndLoc;
8171
+
8172
+ ParserStatus listStatus = parsePrecedenceGroupNameList (*this ,
8173
+ [&](SourceLoc prevCommaLoc, DeclNameRef name, DeclNameLoc nameLoc) {
8174
+ if (!isPrefix && !isPostfix && groupName.empty ()) {
8175
+ // For infix operator declarations, the first element is assumed to be
8176
+ // a real precedence group.
8177
+ groupName = name.getBaseIdentifier ();
8178
+ groupLoc = nameLoc.getBaseNameLoc ();
8179
+ } else {
8180
+ // This is an excess element. Update excessStartLoc and excessEndLoc to
8181
+ // include it in the range to diagnose.
8182
+ if (excessStartLoc.isInvalid ())
8183
+ excessStartLoc = prevCommaLoc;
8184
+ excessEndLoc = nameLoc.getEndLoc ();
8185
+ }
8186
+ });
8139
8187
8140
- if (Context.TypeCheckerOpts .EnableOperatorDesignatedTypes ) {
8141
- // Designated types have been removed; consume the list (mainly for source
8142
- // compatibility with old swiftinterfaces) and emit a warning.
8188
+ if (listStatus.isErrorOrHasCompletion ())
8189
+ return makeParserResult<OperatorDecl>(listStatus, nullptr );
8143
8190
8144
- // These SourceLocs point to the ends of the designated type list. If
8145
- // `typesEndLoc` never becomes valid, we didn't find any designated types.
8146
- SourceLoc typesStartLoc = Tok.getLoc ();
8147
- SourceLoc typesEndLoc;
8191
+ // Nothing to complete here, simply consume the token.
8192
+ if (Tok.is (tok::code_complete))
8193
+ consumeToken ();
8148
8194
8149
- if (isPrefix || isPostfix) {
8150
- // These have no precedence group, so we already parsed the first entry
8151
- // in the designated types list. Retroactively include it in the range.
8152
- typesStartLoc = colonLoc;
8153
- typesEndLoc = groupLoc;
8154
- }
8195
+ if (excessEndLoc.isValid ()) {
8196
+ auto diagID = !isPrefix && !isPostfix ? diag::precedencegroup_too_many
8197
+ : diag::precedencegroup_not_infix;
8155
8198
8156
- while (consumeIf (tok::comma, typesEndLoc)) {
8157
- if (Tok.isNot (tok::eof))
8158
- typesEndLoc = consumeToken ();
8159
- }
8199
+ if (Context.TypeCheckerOpts .EnableOperatorDesignatedTypes )
8200
+ diagID = diag::operator_decl_remove_designated_types;
8160
8201
8161
- if (typesEndLoc.isValid ())
8162
- diagnose (typesStartLoc, diag::operator_decl_remove_designated_types)
8163
- .fixItRemove ({typesStartLoc, typesEndLoc});
8164
- } else {
8165
- if (isPrefix || isPostfix) {
8166
- diagnose (colonLoc, diag::precedencegroup_not_infix)
8167
- .fixItRemove ({colonLoc, groupLoc});
8168
- }
8169
- // Nothing to complete here, simply consume the token.
8170
- if (Tok.is (tok::code_complete))
8171
- consumeToken ();
8202
+ diagnose (excessStartLoc, diagID)
8203
+ .fixItRemove ({excessStartLoc, excessEndLoc});
8172
8204
}
8173
8205
}
8174
8206
8175
8207
// Diagnose deprecated operator body syntax `operator + { ... }`.
8208
+ SourceLoc lastGoodLoc = PreviousLoc;
8176
8209
SourceLoc lBraceLoc;
8177
8210
if (consumeIf (tok::l_brace, lBraceLoc)) {
8178
8211
if (isInfix && !Tok.is (tok::r_brace)) {
8179
8212
diagnose (lBraceLoc, diag::deprecated_operator_body_use_group);
8180
8213
} else {
8181
8214
auto Diag = diagnose (lBraceLoc, diag::deprecated_operator_body);
8182
8215
if (Tok.is (tok::r_brace)) {
8183
- SourceLoc lastGoodLoc = groupLoc.isValid () ? groupLoc : NameLoc;
8184
8216
SourceLoc lastGoodLocEnd = Lexer::getLocForEndOfToken (SourceMgr,
8185
8217
lastGoodLoc);
8186
8218
SourceLoc rBraceEnd = Lexer::getLocForEndOfToken (SourceMgr, Tok.getLoc ());
@@ -8420,28 +8452,14 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags,
8420
8452
: higherThanKeywordLoc);
8421
8453
auto &relations = (isLowerThan ? lowerThan : higherThan);
8422
8454
8423
- do {
8424
- SyntaxParsingContext NameCtxt (SyntaxContext,
8425
- SyntaxKind::PrecedenceGroupNameElement);
8426
- if (checkCodeCompletion (SyntaxKind::PrecedenceGroupRelation)) {
8427
- return abortBody (/* hasCodeCompletion*/ true );
8428
- }
8429
-
8430
- if (Tok.isNot (tok::identifier)) {
8431
- diagnose (Tok, diag::expected_precedencegroup_relation, attrName);
8432
- return abortBody ();
8433
- }
8434
- Identifier name;
8435
- SourceLoc nameLoc = consumeIdentifier (name,
8436
- /* diagnoseDollarPrefix=*/ false );
8437
- relations.push_back ({nameLoc, name, nullptr });
8438
-
8439
- if (skipUnspacedCodeCompleteToken ())
8440
- return abortBody (/* hasCodeCompletion*/ true );
8441
- if (!consumeIf (tok::comma))
8442
- break ;
8443
- } while (true );
8444
- SyntaxContext->collectNodesInPlace (SyntaxKind::PrecedenceGroupNameList);
8455
+ ParserStatus listStatus = parsePrecedenceGroupNameList (*this ,
8456
+ [&](SourceLoc prevCommaLoc, DeclNameRef name, DeclNameLoc nameLoc) {
8457
+ relations.push_back ({nameLoc.getBaseNameLoc (), name.getBaseIdentifier (),
8458
+ nullptr });
8459
+ });
8460
+ if (listStatus.isErrorOrHasCompletion ()) {
8461
+ return abortBody (listStatus.hasCodeCompletion ());
8462
+ }
8445
8463
continue ;
8446
8464
}
8447
8465
0 commit comments