Ungate accepted parts of SE439

This commit is contained in:
Mateus Rodrigues
2024-07-22 09:55:16 -03:00
parent e1f537107f
commit e0d416cdab
6 changed files with 525 additions and 522 deletions

View File

@@ -213,347 +213,356 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
// Parse the parameter list.
bool isClosure = paramContext == ParameterContextKind::Closure;
return parseList(tok::r_paren, leftParenLoc, rightParenLoc,
/*AllowSepAfterLast=*/Context.LangOpts.hasFeature(Feature::TrailingComma),
diag::expected_rparen_parameter,
[&]() -> ParserStatus {
ParsedParameter param;
ParserStatus status;
SourceLoc StartLoc = Tok.getLoc();
return parseList(
tok::r_paren, leftParenLoc, rightParenLoc,
/*AllowSepAfterLast=*/true, diag::expected_rparen_parameter,
[&]() -> ParserStatus {
ParsedParameter param;
ParserStatus status;
SourceLoc StartLoc = Tok.getLoc();
unsigned defaultArgIndex = defaultArgs ? defaultArgs->NextIndex++ : 0;
unsigned defaultArgIndex = defaultArgs ? defaultArgs->NextIndex++ : 0;
// Attributes.
if (paramContext != ParameterContextKind::EnumElement) {
auto AttrStatus = parseDeclAttributeList(param.Attrs);
if (AttrStatus.hasCodeCompletion()) {
if (this->CodeCompletionCallbacks)
this->CodeCompletionCallbacks->setAttrTargetDeclKind(DeclKind::Param);
status.setHasCodeCompletionAndIsError();
}
}
{
// ('inout' | '__shared' | '__owned' | isolated)?
bool hasSpecifier = false;
while (isParameterSpecifier()) {
// Placing 'inout' in front of the parameter specifiers was allowed in
// the Swift 2-ish era and got moved to the return type in Swift 3
// (SE-0031).
// But new parameters that don't store there location in
// `SpecifierLoc` were added afterwards and didn't get diagnosed.
// We thus need to parameter specifiers that don't store their location
// in `SpecifierLoc` here. `SpecifierLoc` parameters get diagnosed in
// `validateParameterWithOwnership`
// is this token the identifier of an argument label? `inout` is a
// reserved keyword but the other modifiers are not.
if (!Tok.is(tok::kw_inout)) {
bool partOfArgumentLabel = lookahead<bool>(1, [&](CancellableBacktrackingScope &) {
if (Tok.is(tok::colon))
return true; // isolated :
return Tok.canBeArgumentLabel() && peekToken().is(tok::colon);
});
if (partOfArgumentLabel)
break;
}
if (Tok.isContextualKeyword("isolated")) {
diagnose(Tok, diag::parameter_specifier_as_attr_disallowed, Tok.getText())
.warnUntilSwiftVersion(6);
// did we already find an 'isolated' type modifier?
if (param.IsolatedLoc.isValid()) {
diagnose(Tok, diag::parameter_specifier_repeated)
.fixItRemove(Tok.getLoc());
consumeToken();
continue;
// Attributes.
if (paramContext != ParameterContextKind::EnumElement) {
auto AttrStatus = parseDeclAttributeList(param.Attrs);
if (AttrStatus.hasCodeCompletion()) {
if (this->CodeCompletionCallbacks)
this->CodeCompletionCallbacks->setAttrTargetDeclKind(
DeclKind::Param);
status.setHasCodeCompletionAndIsError();
}
// consume 'isolated' as type modifier
param.IsolatedLoc = consumeToken();
continue;
}
if (Tok.isContextualKeyword("_const")) {
diagnose(Tok, diag::parameter_specifier_as_attr_disallowed, Tok.getText())
.warnUntilSwiftVersion(6);
param.CompileConstLoc = consumeToken();
continue;
}
{
// ('inout' | '__shared' | '__owned' | isolated)?
bool hasSpecifier = false;
while (isParameterSpecifier()) {
// Placing 'inout' in front of the parameter specifiers was allowed
// in the Swift 2-ish era and got moved to the return type in Swift
// 3 (SE-0031). But new parameters that don't store there location
// in `SpecifierLoc` were added afterwards and didn't get diagnosed.
// We thus need to parameter specifiers that don't store their
// location in `SpecifierLoc` here. `SpecifierLoc` parameters get
// diagnosed in `validateParameterWithOwnership`
if (Context.LangOpts.hasFeature(Feature::SendingArgsAndResults) &&
Tok.isContextualKeyword("transferring")) {
diagnose(Tok, diag::parameter_specifier_as_attr_disallowed, Tok.getText())
.warnUntilSwiftVersion(6);
if (param.TransferringLoc.isValid()) {
diagnose(Tok, diag::parameter_specifier_repeated)
.fixItRemove(Tok.getLoc());
consumeToken();
continue;
}
// is this token the identifier of an argument label? `inout` is a
// reserved keyword but the other modifiers are not.
if (!Tok.is(tok::kw_inout)) {
bool partOfArgumentLabel =
lookahead<bool>(1, [&](CancellableBacktrackingScope &) {
if (Tok.is(tok::colon))
return true; // isolated :
diagnose(Tok, diag::transferring_is_now_sendable)
.fixItReplace(Tok.getLoc(), "sending");
return Tok.canBeArgumentLabel() &&
peekToken().is(tok::colon);
});
if (param.SendingLoc.isValid()) {
diagnose(Tok, diag::sending_and_transferring_used_together)
.fixItRemove(Tok.getLoc());
consumeToken();
continue;
}
if (partOfArgumentLabel)
break;
}
param.TransferringLoc = consumeToken();
continue;
}
if (Tok.isContextualKeyword("isolated")) {
diagnose(Tok, diag::parameter_specifier_as_attr_disallowed,
Tok.getText())
.warnUntilSwiftVersion(6);
// did we already find an 'isolated' type modifier?
if (param.IsolatedLoc.isValid()) {
diagnose(Tok, diag::parameter_specifier_repeated)
.fixItRemove(Tok.getLoc());
consumeToken();
continue;
}
if (Context.LangOpts.hasFeature(Feature::SendingArgsAndResults) &&
Tok.isContextualKeyword("sending")) {
diagnose(Tok, diag::parameter_specifier_as_attr_disallowed,
Tok.getText())
.warnUntilSwiftVersion(6);
if (param.SendingLoc.isValid()) {
diagnose(Tok, diag::parameter_specifier_repeated)
.fixItRemove(Tok.getLoc());
consumeToken();
continue;
}
// consume 'isolated' as type modifier
param.IsolatedLoc = consumeToken();
continue;
}
if (param.TransferringLoc.isValid()) {
diagnose(Tok, diag::sending_and_transferring_used_together)
.fixItRemove(param.TransferringLoc);
consumeToken();
continue;
}
if (Tok.isContextualKeyword("_const")) {
diagnose(Tok, diag::parameter_specifier_as_attr_disallowed,
Tok.getText())
.warnUntilSwiftVersion(6);
param.CompileConstLoc = consumeToken();
continue;
}
param.SendingLoc = consumeToken();
continue;
}
if (Context.LangOpts.hasFeature(Feature::SendingArgsAndResults) &&
Tok.isContextualKeyword("transferring")) {
diagnose(Tok, diag::parameter_specifier_as_attr_disallowed,
Tok.getText())
.warnUntilSwiftVersion(6);
if (param.TransferringLoc.isValid()) {
diagnose(Tok, diag::parameter_specifier_repeated)
.fixItRemove(Tok.getLoc());
consumeToken();
continue;
}
if (!hasSpecifier) {
// These cases are handled later when mapping to ParamDecls for
// better fixits.
if (Tok.is(tok::kw_inout)) {
param.SpecifierKind = ParamDecl::Specifier::InOut;
param.SpecifierLoc = consumeToken();
} else if (Tok.isContextualKeyword("borrowing")) {
param.SpecifierKind = ParamDecl::Specifier::Borrowing;
param.SpecifierLoc = consumeToken();
} else if (Tok.isContextualKeyword("consuming")) {
param.SpecifierKind = ParamDecl::Specifier::Consuming;
param.SpecifierLoc = consumeToken();
} else if (Tok.isContextualKeyword("__shared")) {
param.SpecifierKind = ParamDecl::Specifier::LegacyShared;
param.SpecifierLoc = consumeToken();
} else if (Tok.isContextualKeyword("__owned")) {
param.SpecifierKind = ParamDecl::Specifier::LegacyOwned;
param.SpecifierLoc = consumeToken();
}
diagnose(Tok, diag::transferring_is_now_sendable)
.fixItReplace(Tok.getLoc(), "sending");
if (param.SendingLoc.isValid()) {
diagnose(Tok, diag::sending_before_parameter_specifier,
getNameForParamSpecifier(param.SpecifierKind));
}
if (param.SendingLoc.isValid()) {
diagnose(Tok, diag::sending_and_transferring_used_together)
.fixItRemove(Tok.getLoc());
consumeToken();
continue;
}
hasSpecifier = true;
} else {
// Redundant specifiers are fairly common, recognize, reject, and
// recover from this gracefully.
diagnose(Tok, diag::parameter_specifier_repeated)
.fixItRemove(Tok.getLoc());
consumeToken();
}
}
}
// If let or var is being used as an argument label, allow it but
// generate a warning.
if (!isClosure &&
(Tok.isAny(tok::kw_let, tok::kw_var) ||
(Context.LangOpts.hasFeature(Feature::ReferenceBindings) &&
Tok.isAny(tok::kw_inout)))) {
diagnose(Tok, diag::parameter_let_var_as_attr, Tok.getText())
.fixItReplace(Tok.getLoc(), "`" + Tok.getText().str() + "`");
}
param.TransferringLoc = consumeToken();
continue;
}
auto parseParamType = [&]() -> ParserResult<TypeRepr> {
// Currently none of the parameter type completions are relevant for
// enum cases, so don't include them. We'll complete for a regular type
// beginning instead.
if (paramContext != ParameterContextKind::EnumElement) {
if (auto CCLoc = tryCompleteFunctionParamTypeBeginning()) {
auto *ET = ErrorTypeRepr::create(Context, CCLoc);
return makeParserCodeCompletionResult<TypeRepr>(ET);
}
}
return parseType(diag::expected_parameter_type);
};
if (Context.LangOpts.hasFeature(Feature::SendingArgsAndResults) &&
Tok.isContextualKeyword("sending")) {
diagnose(Tok, diag::parameter_specifier_as_attr_disallowed,
Tok.getText())
.warnUntilSwiftVersion(6);
if (param.SendingLoc.isValid()) {
diagnose(Tok, diag::parameter_specifier_repeated)
.fixItRemove(Tok.getLoc());
consumeToken();
continue;
}
if (startsParameterName(isClosure)) {
// identifier-or-none for the first name
param.FirstNameLoc = consumeArgumentLabel(param.FirstName,
/*diagnoseDollarPrefix=*/!isClosure);
if (param.TransferringLoc.isValid()) {
diagnose(Tok, diag::sending_and_transferring_used_together)
.fixItRemove(param.TransferringLoc);
consumeToken();
continue;
}
// identifier-or-none? for the second name
if (Tok.canBeArgumentLabel())
param.SecondNameLoc = consumeArgumentLabel(param.SecondName,
/*diagnoseDollarPrefix=*/true);
param.SendingLoc = consumeToken();
continue;
}
// Operators, closures, and enum elements cannot have API names.
if ((paramContext == ParameterContextKind::Operator ||
paramContext == ParameterContextKind::Closure ||
paramContext == ParameterContextKind::EnumElement) &&
!param.FirstName.empty() &&
param.SecondNameLoc.isValid()) {
enum KeywordArgumentDiagnosticContextKind {
Operator = 0,
Closure = 1,
EnumElement = 2,
} diagContextKind;
if (!hasSpecifier) {
// These cases are handled later when mapping to ParamDecls for
// better fixits.
if (Tok.is(tok::kw_inout)) {
param.SpecifierKind = ParamDecl::Specifier::InOut;
param.SpecifierLoc = consumeToken();
} else if (Tok.isContextualKeyword("borrowing")) {
param.SpecifierKind = ParamDecl::Specifier::Borrowing;
param.SpecifierLoc = consumeToken();
} else if (Tok.isContextualKeyword("consuming")) {
param.SpecifierKind = ParamDecl::Specifier::Consuming;
param.SpecifierLoc = consumeToken();
} else if (Tok.isContextualKeyword("__shared")) {
param.SpecifierKind = ParamDecl::Specifier::LegacyShared;
param.SpecifierLoc = consumeToken();
} else if (Tok.isContextualKeyword("__owned")) {
param.SpecifierKind = ParamDecl::Specifier::LegacyOwned;
param.SpecifierLoc = consumeToken();
}
switch (paramContext) {
case ParameterContextKind::Operator:
diagContextKind = Operator;
break;
case ParameterContextKind::Closure:
diagContextKind = Closure;
break;
case ParameterContextKind::EnumElement:
diagContextKind = EnumElement;
break;
default:
llvm_unreachable("Unhandled parameter context kind!");
}
diagnose(param.FirstNameLoc, diag::parameter_operator_keyword_argument,
unsigned(diagContextKind))
.fixItRemoveChars(param.FirstNameLoc, param.SecondNameLoc);
param.FirstName = param.SecondName;
param.FirstNameLoc = param.SecondNameLoc;
param.SecondName = Identifier();
param.SecondNameLoc = SourceLoc();
}
if (param.SendingLoc.isValid()) {
diagnose(Tok, diag::sending_before_parameter_specifier,
getNameForParamSpecifier(param.SpecifierKind));
}
// (':' type)?
if (consumeIf(tok::colon)) {
auto type = parseParamType();
status |= type;
param.Type = type.getPtrOrNull();
// If we didn't parse a type, then we already diagnosed that the type
// was invalid. Remember that.
if (type.isNull() && !type.hasCodeCompletion())
param.isInvalid = true;
} else if (paramContext != Parser::ParameterContextKind::Closure) {
diagnose(Tok, diag::expected_parameter_colon);
param.isInvalid = true;
}
} else {
// Otherwise, we have invalid code. Check to see if this looks like a
// type. If so, diagnose it as a common error.
bool isBareType = false;
{
BacktrackingScope backtrack(*this);
isBareType = canParseType() && Tok.isAny(tok::comma, tok::r_paren,
tok::equal);
}
if (isBareType && paramContext == ParameterContextKind::EnumElement) {
auto type = parseParamType();
status |= type;
param.Type = type.getPtrOrNull();
param.FirstName = Identifier();
param.FirstNameLoc = SourceLoc();
param.SecondName = Identifier();
param.SecondNameLoc = SourceLoc();
} else if (isBareType && !Tok.is(tok::code_complete)) {
// Otherwise, if this is a bare type, then the user forgot to name the
// parameter, e.g. "func foo(Int) {}"
// Don't enter this case if the element could only be parsed as a bare
// type because a code completion token is positioned here. In this case
// the user is about to type the parameter label and we shouldn't
// suggest types.
SourceLoc typeStartLoc = Tok.getLoc();
auto type = parseParamType();
status |= type;
param.Type = type.getPtrOrNull();
// If this is a closure declaration, what is going
// on is most likely argument destructuring, we are going
// to diagnose that after all of the parameters are parsed.
if (param.Type) {
// Mark current parameter type as invalid so it is possible
// to diagnose it as destructuring of the closure parameter list.
param.isPotentiallyDestructured = true;
if (!isClosure) {
// Unnamed parameters must be written as "_: Type".
diagnose(typeStartLoc, diag::parameter_unnamed)
.fixItInsert(typeStartLoc, "_: ");
} else {
// Unnamed parameters were accidentally possibly accepted after
// SE-110 depending on the kind of declaration. We now need to
// warn about the misuse of this syntax and offer to
// fix it.
// An exception to this rule is when the type is declared with type sugar
// Reference: https://github.com/apple/swift/issues/54133
if (isa<OptionalTypeRepr>(param.Type)
|| isa<ImplicitlyUnwrappedOptionalTypeRepr>(param.Type)) {
diagnose(typeStartLoc, diag::parameter_unnamed)
.fixItInsert(typeStartLoc, "_: ");
hasSpecifier = true;
} else {
diagnose(typeStartLoc, diag::parameter_unnamed)
.warnUntilSwiftVersion(6)
.fixItInsert(typeStartLoc, "_: ");
// Redundant specifiers are fairly common, recognize, reject, and
// recover from this gracefully.
diagnose(Tok, diag::parameter_specifier_repeated)
.fixItRemove(Tok.getLoc());
consumeToken();
}
}
}
} else {
// Otherwise, we're not sure what is going on, but this doesn't smell
// like a parameter.
diagnose(Tok, diag::expected_parameter_name);
param.isInvalid = true;
param.FirstNameLoc = Tok.getLoc();
TokReceiver->registerTokenKindChange(param.FirstNameLoc,
tok::identifier);
status.setIsParseError();
}
}
// If this parameter had an ellipsis, check it has a TypeRepr.
if (Tok.isEllipsis()) {
if (param.Type == nullptr && !param.isInvalid) {
diagnose(Tok, diag::untyped_pattern_ellipsis);
consumeToken();
}
}
// If let or var is being used as an argument label, allow it but
// generate a warning.
if (!isClosure &&
(Tok.isAny(tok::kw_let, tok::kw_var) ||
(Context.LangOpts.hasFeature(Feature::ReferenceBindings) &&
Tok.isAny(tok::kw_inout)))) {
diagnose(Tok, diag::parameter_let_var_as_attr, Tok.getText())
.fixItReplace(Tok.getLoc(), "`" + Tok.getText().str() + "`");
}
// ('=' expr) or ('==' expr)?
bool isEqualBinaryOperator =
Tok.isBinaryOperator() && Tok.getText() == "==";
if (Tok.is(tok::equal) || isEqualBinaryOperator) {
SourceLoc EqualLoc = Tok.getLoc();
auto parseParamType = [&]() -> ParserResult<TypeRepr> {
// Currently none of the parameter type completions are relevant for
// enum cases, so don't include them. We'll complete for a regular
// type beginning instead.
if (paramContext != ParameterContextKind::EnumElement) {
if (auto CCLoc = tryCompleteFunctionParamTypeBeginning()) {
auto *ET = ErrorTypeRepr::create(Context, CCLoc);
return makeParserCodeCompletionResult<TypeRepr>(ET);
}
}
return parseType(diag::expected_parameter_type);
};
if (isEqualBinaryOperator) {
diagnose(Tok, diag::expected_assignment_instead_of_comparison_operator)
.fixItReplace(EqualLoc, "=");
}
if (startsParameterName(isClosure)) {
// identifier-or-none for the first name
param.FirstNameLoc =
consumeArgumentLabel(param.FirstName,
/*diagnoseDollarPrefix=*/!isClosure);
status |= parseDefaultArgument(*this, defaultArgs, defaultArgIndex,
param.DefaultArg, paramContext);
}
// identifier-or-none? for the second name
if (Tok.canBeArgumentLabel())
param.SecondNameLoc =
consumeArgumentLabel(param.SecondName,
/*diagnoseDollarPrefix=*/true);
// If we haven't made progress, don't add the parameter.
if (Tok.getLoc() == StartLoc) {
// If we took a default argument index for this parameter, but didn't add
// one, then give it back.
if (defaultArgs) --defaultArgs->NextIndex;
return status;
}
// Operators, closures, and enum elements cannot have API names.
if ((paramContext == ParameterContextKind::Operator ||
paramContext == ParameterContextKind::Closure ||
paramContext == ParameterContextKind::EnumElement) &&
!param.FirstName.empty() && param.SecondNameLoc.isValid()) {
enum KeywordArgumentDiagnosticContextKind {
Operator = 0,
Closure = 1,
EnumElement = 2,
} diagContextKind;
params.push_back(param);
return status;
});
switch (paramContext) {
case ParameterContextKind::Operator:
diagContextKind = Operator;
break;
case ParameterContextKind::Closure:
diagContextKind = Closure;
break;
case ParameterContextKind::EnumElement:
diagContextKind = EnumElement;
break;
default:
llvm_unreachable("Unhandled parameter context kind!");
}
diagnose(param.FirstNameLoc,
diag::parameter_operator_keyword_argument,
unsigned(diagContextKind))
.fixItRemoveChars(param.FirstNameLoc, param.SecondNameLoc);
param.FirstName = param.SecondName;
param.FirstNameLoc = param.SecondNameLoc;
param.SecondName = Identifier();
param.SecondNameLoc = SourceLoc();
}
// (':' type)?
if (consumeIf(tok::colon)) {
auto type = parseParamType();
status |= type;
param.Type = type.getPtrOrNull();
// If we didn't parse a type, then we already diagnosed that the
// type was invalid. Remember that.
if (type.isNull() && !type.hasCodeCompletion())
param.isInvalid = true;
} else if (paramContext != Parser::ParameterContextKind::Closure) {
diagnose(Tok, diag::expected_parameter_colon);
param.isInvalid = true;
}
} else {
// Otherwise, we have invalid code. Check to see if this looks like a
// type. If so, diagnose it as a common error.
bool isBareType = false;
{
BacktrackingScope backtrack(*this);
isBareType = canParseType() &&
Tok.isAny(tok::comma, tok::r_paren, tok::equal);
}
if (isBareType && paramContext == ParameterContextKind::EnumElement) {
auto type = parseParamType();
status |= type;
param.Type = type.getPtrOrNull();
param.FirstName = Identifier();
param.FirstNameLoc = SourceLoc();
param.SecondName = Identifier();
param.SecondNameLoc = SourceLoc();
} else if (isBareType && !Tok.is(tok::code_complete)) {
// Otherwise, if this is a bare type, then the user forgot to name
// the parameter, e.g. "func foo(Int) {}" Don't enter this case if
// the element could only be parsed as a bare type because a code
// completion token is positioned here. In this case the user is
// about to type the parameter label and we shouldn't suggest types.
SourceLoc typeStartLoc = Tok.getLoc();
auto type = parseParamType();
status |= type;
param.Type = type.getPtrOrNull();
// If this is a closure declaration, what is going
// on is most likely argument destructuring, we are going
// to diagnose that after all of the parameters are parsed.
if (param.Type) {
// Mark current parameter type as invalid so it is possible
// to diagnose it as destructuring of the closure parameter list.
param.isPotentiallyDestructured = true;
if (!isClosure) {
// Unnamed parameters must be written as "_: Type".
diagnose(typeStartLoc, diag::parameter_unnamed)
.fixItInsert(typeStartLoc, "_: ");
} else {
// Unnamed parameters were accidentally possibly accepted after
// SE-110 depending on the kind of declaration. We now need to
// warn about the misuse of this syntax and offer to
// fix it.
// An exception to this rule is when the type is declared with
// type sugar Reference:
// https://github.com/apple/swift/issues/54133
if (isa<OptionalTypeRepr>(param.Type) ||
isa<ImplicitlyUnwrappedOptionalTypeRepr>(param.Type)) {
diagnose(typeStartLoc, diag::parameter_unnamed)
.fixItInsert(typeStartLoc, "_: ");
} else {
diagnose(typeStartLoc, diag::parameter_unnamed)
.warnUntilSwiftVersion(6)
.fixItInsert(typeStartLoc, "_: ");
}
}
}
} else {
// Otherwise, we're not sure what is going on, but this doesn't
// smell like a parameter.
diagnose(Tok, diag::expected_parameter_name);
param.isInvalid = true;
param.FirstNameLoc = Tok.getLoc();
TokReceiver->registerTokenKindChange(param.FirstNameLoc,
tok::identifier);
status.setIsParseError();
}
}
// If this parameter had an ellipsis, check it has a TypeRepr.
if (Tok.isEllipsis()) {
if (param.Type == nullptr && !param.isInvalid) {
diagnose(Tok, diag::untyped_pattern_ellipsis);
consumeToken();
}
}
// ('=' expr) or ('==' expr)?
bool isEqualBinaryOperator =
Tok.isBinaryOperator() && Tok.getText() == "==";
if (Tok.is(tok::equal) || isEqualBinaryOperator) {
SourceLoc EqualLoc = Tok.getLoc();
if (isEqualBinaryOperator) {
diagnose(Tok,
diag::expected_assignment_instead_of_comparison_operator)
.fixItReplace(EqualLoc, "=");
}
status |= parseDefaultArgument(*this, defaultArgs, defaultArgIndex,
param.DefaultArg, paramContext);
}
// If we haven't made progress, don't add the parameter.
if (Tok.getLoc() == StartLoc) {
// If we took a default argument index for this parameter, but didn't
// add one, then give it back.
if (defaultArgs)
--defaultArgs->NextIndex;
return status;
}
params.push_back(param);
return status;
});
}
static TypeRepr *
@@ -1312,24 +1321,23 @@ ParserResult<Pattern> Parser::parsePatternTuple() {
// Parse all the elements.
SmallVector<TuplePatternElt, 8> elts;
ParserStatus ListStatus =
parseList(tok::r_paren, LPLoc, RPLoc,
/*AllowSepAfterLast=*/Context.LangOpts.hasFeature(Feature::TrailingComma),
diag::expected_rparen_tuple_pattern_list,
[&] () -> ParserStatus {
// Parse the pattern tuple element.
ParserStatus EltStatus;
std::optional<TuplePatternElt> elt;
std::tie(EltStatus, elt) = parsePatternTupleElement();
if (EltStatus.hasCodeCompletion())
return makeParserCodeCompletionStatus();
if (!elt)
return makeParserError();
ParserStatus ListStatus = parseList(
tok::r_paren, LPLoc, RPLoc,
/*AllowSepAfterLast=*/true, diag::expected_rparen_tuple_pattern_list,
[&]() -> ParserStatus {
// Parse the pattern tuple element.
ParserStatus EltStatus;
std::optional<TuplePatternElt> elt;
std::tie(EltStatus, elt) = parsePatternTupleElement();
if (EltStatus.hasCodeCompletion())
return makeParserCodeCompletionStatus();
if (!elt)
return makeParserError();
// Add this element to the list.
elts.push_back(*elt);
return makeParserSuccess();
});
// Add this element to the list.
elts.push_back(*elt);
return makeParserSuccess();
});
return makeParserResult(
ListStatus,