[libSyntax] Model parameter modifiers as a ModifierList

This fixes a libSyntax misparse where the first parameter name was parsed as the `isolated` token.
This commit is contained in:
Alex Hoppen
2022-09-30 14:05:15 +02:00
parent 8491f52d47
commit 14d0f41ca7
3 changed files with 865 additions and 58 deletions

View File

@@ -254,70 +254,75 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
status.setHasCodeCompletionAndIsError();
}
}
// ('inout' | '__shared' | '__owned' | isolated)?
bool hasSpecifier = false;
while (Tok.is(tok::kw_inout) ||
Tok.isContextualKeyword("__shared") ||
Tok.isContextualKeyword("__owned") ||
Tok.isContextualKeyword("isolated") ||
Tok.isContextualKeyword("_const")) {
if (Tok.isContextualKeyword("isolated")) {
// did we already find an 'isolated' type modifier?
if (param.IsolatedLoc.isValid()) {
diagnose(Tok, diag::parameter_specifier_repeated)
{
SyntaxParsingContext ModifiersContext(SyntaxContext, SyntaxKind::ModifierList);
// ('inout' | '__shared' | '__owned' | isolated)?
bool hasSpecifier = false;
while (Tok.is(tok::kw_inout) ||
Tok.isContextualKeyword("__shared") ||
Tok.isContextualKeyword("__owned") ||
Tok.isContextualKeyword("isolated") ||
Tok.isContextualKeyword("_const")) {
SyntaxParsingContext ModContext(SyntaxContext, SyntaxKind::DeclModifier);
if (Tok.isContextualKeyword("isolated")) {
// did we already find an 'isolated' type modifier?
if (param.IsolatedLoc.isValid()) {
diagnose(Tok, diag::parameter_specifier_repeated)
.fixItRemove(Tok.getLoc());
consumeToken();
consumeToken();
continue;
}
// is this 'isolated' token the identifier of an argument label?
bool partOfArgumentLabel = lookahead<bool>(1, [&](CancellableBacktrackingScope &) {
if (Tok.is(tok::colon))
return true; // isolated :
// isolated x :
return Tok.canBeArgumentLabel() && peekToken().is(tok::colon);
});
if (partOfArgumentLabel)
break;
// consume 'isolated' as type modifier
param.IsolatedLoc = consumeToken();
continue;
}
// is this 'isolated' token the identifier of an argument label?
bool partOfArgumentLabel = lookahead<bool>(1, [&](CancellableBacktrackingScope &) {
if (Tok.is(tok::colon))
return true; // isolated :
// isolated x :
return Tok.canBeArgumentLabel() && peekToken().is(tok::colon);
});
if (partOfArgumentLabel)
break;
// consume 'isolated' as type modifier
param.IsolatedLoc = consumeToken();
continue;
}
if (Tok.isContextualKeyword("_const")) {
param.CompileConstLoc = consumeToken();
continue;
}
if (!hasSpecifier) {
if (Tok.is(tok::kw_inout)) {
// This case is handled later when mapping to ParamDecls for
// better fixits.
param.SpecifierKind = ParamDecl::Specifier::InOut;
param.SpecifierLoc = consumeToken();
} else if (Tok.isContextualKeyword("__shared")) {
// This case is handled later when mapping to ParamDecls for
// better fixits.
param.SpecifierKind = ParamDecl::Specifier::Shared;
param.SpecifierLoc = consumeToken();
} else if (Tok.isContextualKeyword("__owned")) {
// This case is handled later when mapping to ParamDecls for
// better fixits.
param.SpecifierKind = ParamDecl::Specifier::Owned;
param.SpecifierLoc = consumeToken();
if (Tok.isContextualKeyword("_const")) {
param.CompileConstLoc = consumeToken();
continue;
}
if (!hasSpecifier) {
if (Tok.is(tok::kw_inout)) {
// This case is handled later when mapping to ParamDecls for
// better fixits.
param.SpecifierKind = ParamDecl::Specifier::InOut;
param.SpecifierLoc = consumeToken();
} else if (Tok.isContextualKeyword("__shared")) {
// This case is handled later when mapping to ParamDecls for
// better fixits.
param.SpecifierKind = ParamDecl::Specifier::Shared;
param.SpecifierLoc = consumeToken();
} else if (Tok.isContextualKeyword("__owned")) {
// This case is handled later when mapping to ParamDecls for
// better fixits.
param.SpecifierKind = ParamDecl::Specifier::Owned;
param.SpecifierLoc = consumeToken();
}
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();
}
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();
}
}