Skip to content

Commit 3d1ad49

Browse files
committed
corrected implementation of parsing nonisolated(unsafe) as decl contextual keyword in top-level global scope (follow up to 5a88257)
1 parent bc20be5 commit 3d1ad49

File tree

1 file changed

+37
-27
lines changed

1 file changed

+37
-27
lines changed

lib/Parse/ParseDecl.cpp

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "llvm/Support/Path.h"
4444
#include "llvm/Support/SaveAndRestore.h"
4545
#include <algorithm>
46+
#include <initializer_list>
4647

4748
using namespace swift;
4849

@@ -5143,18 +5144,34 @@ bool swift::isKeywordPossibleDeclStart(const LangOptions &options,
51435144
}
51445145
}
51455146

5146-
/// Given a current token of 'unowned', check to see if it is followed by a
5147-
/// "(safe)" or "(unsafe)" specifier.
5148-
static bool isParenthesizedUnowned(Parser &P) {
5149-
assert(P.Tok.getText() == "unowned" && P.peekToken().is(tok::l_paren) &&
5147+
static bool
5148+
isParenthesizedModifier(Parser &P, StringRef name,
5149+
std::initializer_list<StringRef> allowedArguments) {
5150+
assert((P.Tok.getText() == name) && P.peekToken().is(tok::l_paren) &&
51505151
"Invariant violated");
5151-
5152+
51525153
// Look ahead to parse the parenthesized expression.
51535154
Parser::BacktrackingScope Backtrack(P);
51545155
P.consumeToken(tok::identifier);
51555156
P.consumeToken(tok::l_paren);
5156-
return P.Tok.is(tok::identifier) && P.peekToken().is(tok::r_paren) &&
5157-
(P.Tok.getText() == "safe" || P.Tok.getText() == "unsafe");
5157+
5158+
const bool argumentIsAllowed =
5159+
std::find(allowedArguments.begin(), allowedArguments.end(),
5160+
P.Tok.getText()) != allowedArguments.end();
5161+
return argumentIsAllowed && P.Tok.is(tok::identifier) &&
5162+
P.peekToken().is(tok::r_paren);
5163+
}
5164+
5165+
/// Given a current token of 'unowned', check to see if it is followed by a
5166+
/// "(safe)" or "(unsafe)" specifier.
5167+
static bool isParenthesizedUnowned(Parser &P) {
5168+
return isParenthesizedModifier(P, "unowned", {"safe", "unsafe"});
5169+
}
5170+
5171+
/// Given a current token of 'nonisolated', check to see if it is followed by an
5172+
/// "(unsafe)" specifier.
5173+
static bool isParenthesizedNonisolated(Parser &P) {
5174+
return isParenthesizedModifier(P, "nonisolated", {"unsafe"});
51585175
}
51595176

51605177
static void skipAttribute(Parser &P) {
@@ -5184,30 +5201,10 @@ static void skipAttribute(Parser &P) {
51845201

51855202
bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes,
51865203
bool hadAttrsOrModifiers) {
5187-
const bool isTopLevelLibrary = (SF.Kind == SourceFileKind::Library) ||
5188-
(SF.Kind == SourceFileKind::Interface) ||
5189-
(SF.Kind == SourceFileKind::SIL);
51905204
if (Tok.is(tok::at_sign) && peekToken().is(tok::kw_rethrows)) {
51915205
// @rethrows does not follow the general rule of @<identifier> so
51925206
// it is needed to short circuit this else there will be an infinite
51935207
// loop on invalid attributes of just rethrows
5194-
} else if (Context.LangOpts.hasFeature(Feature::GlobalConcurrency) &&
5195-
(Tok.getKind() == tok::identifier) &&
5196-
Tok.getText().equals("nonisolated") && isTopLevelLibrary &&
5197-
!CurDeclContext->isLocalContext()) {
5198-
// TODO: hack to unblock proposal review by treating top-level nonisolated
5199-
// contextual keyword like an attribute; more robust implementation pending
5200-
BacktrackingScope backtrack(*this);
5201-
skipAttribute(*this);
5202-
5203-
// If this attribute is the last element in the block,
5204-
// consider it is a start of incomplete decl.
5205-
if (Tok.isAny(tok::r_brace, tok::eof) ||
5206-
(Tok.is(tok::pound_endif) && !allowPoundIfAttributes))
5207-
return true;
5208-
5209-
return isStartOfSwiftDecl(allowPoundIfAttributes,
5210-
/*hadAttrsOrModifiers=*/true);
52115208
} else if (!isKeywordPossibleDeclStart(Context.LangOpts, Tok)) {
52125209
// If this is obviously not the start of a decl, then we're done.
52135210
return false;
@@ -5346,6 +5343,19 @@ bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes,
53465343
/*hadAttrsOrModifiers=*/true);
53475344
}
53485345

5346+
// If this is 'nonisolated', check to see if it is valid.
5347+
if (Context.LangOpts.hasFeature(Feature::GlobalConcurrency) &&
5348+
Tok.isContextualKeyword("nonisolated") && Tok2.is(tok::l_paren) &&
5349+
isParenthesizedNonisolated(*this)) {
5350+
BacktrackingScope backtrack(*this);
5351+
consumeToken(tok::identifier);
5352+
consumeToken(tok::l_paren);
5353+
consumeToken(tok::identifier);
5354+
consumeToken(tok::r_paren);
5355+
return isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false,
5356+
/*hadAttrsOrModifiers=*/true);
5357+
}
5358+
53495359
if (Tok.isContextualKeyword("actor")) {
53505360
if (Tok2.is(tok::identifier)) // actor Foo {}
53515361
return true;

0 commit comments

Comments
 (0)