Skip to content

Implementing parsing and printing for 'reasync' functions #35986

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -353,25 +353,25 @@ SIMPLE_DECL_ATTR(testable, Testable,
DECL_ATTR(_alignment, Alignment,
OnStruct | OnEnum |
UserInaccessible |
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
56)
SIMPLE_DECL_ATTR(rethrows, Rethrows,
OnFunc | OnAccessor | OnConstructor |
OnFunc | OnConstructor |
RejectByParser |
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
57)
SIMPLE_DECL_ATTR(rethrows, AtRethrows,
OnProtocol |
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
58)
DECL_ATTR(_swift_native_objc_runtime_base, SwiftNativeObjCRuntimeBase,
OnClass |
UserInaccessible |
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
59)
CONTEXTUAL_SIMPLE_DECL_ATTR(indirect, Indirect, DeclModifier |
OnEnum | OnEnumElement |
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
60)
SIMPLE_DECL_ATTR(warn_unqualified_access, WarnUnqualifiedAccess,
OnFunc | OnAccessor /*| OnVar*/ |
Expand Down Expand Up @@ -469,7 +469,7 @@ DECL_ATTR(_dynamicReplacement, DynamicReplacement,
SIMPLE_DECL_ATTR(_borrowed, Borrowed,
OnVar | OnSubscript | UserInaccessible |
NotSerialized |
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
81)
DECL_ATTR(_private, PrivateImport,
OnImport |
Expand All @@ -479,7 +479,7 @@ DECL_ATTR(_private, PrivateImport,
82)
SIMPLE_DECL_ATTR(_alwaysEmitIntoClient, AlwaysEmitIntoClient,
OnVar | OnSubscript | OnAbstractFunction | UserInaccessible |
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
ABIBreakingToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
83)

SIMPLE_DECL_ATTR(_implementationOnly, ImplementationOnly,
Expand Down Expand Up @@ -613,6 +613,17 @@ SIMPLE_DECL_ATTR(_marker, Marker,
APIBreakingToAdd | APIBreakingToRemove,
108)

SIMPLE_DECL_ATTR(reasync, Reasync,
OnFunc | OnConstructor |
RejectByParser |
ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
109)

SIMPLE_DECL_ATTR(reasync, AtReasync,
OnProtocol |
ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
110)

#undef TYPE_ATTR
#undef DECL_ATTR_ALIAS
#undef CONTEXTUAL_DECL_ATTR_ALIAS
Expand Down
6 changes: 5 additions & 1 deletion include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,9 @@ ERROR(generic_non_function,PointsToFirstBadToken,
ERROR(rethrowing_function_type,none,
"only function declarations may be marked 'rethrows'; "
"did you mean 'throws'?", ())
ERROR(reasync_function_type,none,
"only function declarations may be marked 'reasync'; "
"did you mean 'async'?", ())
ERROR(async_or_throws_in_wrong_position,none,
"'%0' may only occur before '->'", (StringRef))
ERROR(throw_in_function_type,none,
Expand All @@ -745,7 +748,8 @@ ERROR(function_type_argument_label,none,
ERROR(expected_dynamic_func_attr,none,
"expected a dynamically_replaceable function", ())
ERROR(async_after_throws,none,
"'async' must precede %select{'throws'|'rethrows'}0", (bool))
"%select{'async'|'reasync'}0 must precede %select{'throws'|'rethrows'}1",
(bool, bool))
ERROR(async_init,none, "initializer cannot be marked 'async'", ())
ERROR(duplicate_effects_specifier,none,
"'%0' has already been specified", (StringRef))
Expand Down
6 changes: 4 additions & 2 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2994,8 +2994,10 @@ ERROR(override_rethrows_with_non_rethrows,none,
"be 'rethrows'", (bool))
ERROR(rethrows_without_throwing_parameter,none,
"'rethrows' function must take a throwing function argument", ())
ERROR(rethrows_attr_on_non_protocol,none,
"@rethrows may only be used on 'protocol' declarations", ())

ERROR(override_reasync_with_non_reasync,none,
"override of 'reasync' %select{method|initializer}0 should also "
"be 'reasync'", (bool))

ERROR(autoclosure_function_type,none,
"@autoclosure attribute only applies to function types",
Expand Down
8 changes: 6 additions & 2 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1342,6 +1342,7 @@ class Parser {
ParameterList *&bodyParams,
DefaultArgumentInfo &defaultArgs,
SourceLoc &asyncLoc,
bool &reasync,
SourceLoc &throws,
bool &rethrows,
TypeRepr *&retType);
Expand All @@ -1353,11 +1354,14 @@ class Parser {
/// one. Parsing 'async' or 'throws' after the `->` is an error we
/// correct for.
///
/// \param reasync If non-NULL, will also parse the 'reasync' keyword in
/// lieu of 'async'.
///
/// \param rethrows If non-NULL, will also parse the 'rethrows' keyword in
/// lieu of 'throws'.
ParserStatus parseEffectsSpecifiers(SourceLoc existingArrowLoc,
SourceLoc &asyncLoc, SourceLoc &throwsLoc,
bool *rethrows);
SourceLoc &asyncLoc, bool *reasync,
SourceLoc &throwsLoc, bool *rethrows);

/// Returns 'true' if \p T is considered effects specifier.
bool isEffectsSpecifier(const Token &T);
Expand Down
5 changes: 4 additions & 1 deletion lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3152,7 +3152,10 @@ void PrintAST::printFunctionParameters(AbstractFunctionDecl *AFD) {

if (AFD->hasAsync()) {
Printer << " ";
Printer.printKeyword("async", Options);
if (AFD->getAttrs().hasAttribute<ReasyncAttr>())
Printer.printKeyword("reasync", Options);
else
Printer.printKeyword("async", Options);
}

if (AFD->hasThrows()) {
Expand Down
1 change: 1 addition & 0 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
case DAK_ObjCBridged:
case DAK_SynthesizedProtocol:
case DAK_Rethrows:
case DAK_Reasync:
case DAK_Infix:
return false;
case DAK_Override: {
Expand Down
21 changes: 17 additions & 4 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2801,6 +2801,8 @@ ParserStatus Parser::parseDeclAttribute(
// over to the alternate parsing path.
DeclAttrKind DK = DeclAttribute::getAttrKindFromString(Tok.getText());
if (DK == DAK_Rethrows) { DK = DAK_AtRethrows; }
if (DK == DAK_Reasync) { DK = DAK_AtReasync; }

auto checkInvalidAttrName = [&](StringRef invalidName,
StringRef correctName,
DeclAttrKind kind,
Expand Down Expand Up @@ -6694,10 +6696,13 @@ ParserResult<FuncDecl> Parser::parseDeclFunc(SourceLoc StaticLoc,
DeclName FullName;
ParameterList *BodyParams;
SourceLoc asyncLoc;
bool reasync;
SourceLoc throwsLoc;
bool rethrows;
Status |= parseFunctionSignature(SimpleName, FullName, BodyParams,
DefaultArgs, asyncLoc, throwsLoc, rethrows,
DefaultArgs,
asyncLoc, reasync,
throwsLoc, rethrows,
FuncRetTy);
if (Status.hasCodeCompletion() && !CodeCompletion) {
// Trigger delayed parsing, no need to continue.
Expand Down Expand Up @@ -6753,7 +6758,9 @@ ParserResult<FuncDecl> Parser::parseDeclFunc(SourceLoc StaticLoc,
return nullptr;
}

// Add the 'rethrows' attribute.
if (reasync) {
Attributes.add(new (Context) ReasyncAttr(asyncLoc));
}
if (rethrows) {
Attributes.add(new (Context) RethrowsAttr(throwsLoc));
}
Expand Down Expand Up @@ -7725,16 +7732,22 @@ Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
return nullptr;
}

// Parse 'async' / 'throws' / 'rethrows'.
// Parse 'async' / 'reasync' / 'throws' / 'rethrows'.
SourceLoc asyncLoc;
bool reasync = false;
SourceLoc throwsLoc;
bool rethrows = false;
Status |= parseEffectsSpecifiers(SourceLoc(), asyncLoc, throwsLoc, &rethrows);
Status |= parseEffectsSpecifiers(SourceLoc(),
asyncLoc, &reasync,
throwsLoc, &rethrows);
if (Status.hasCodeCompletion() && !CodeCompletion) {
// Trigger delayed parsing, no need to continue.
return Status;
}

if (reasync) {
Attributes.add(new (Context) ReasyncAttr(asyncLoc));
}
if (rethrows) {
Attributes.add(new (Context) RethrowsAttr(throwsLoc));
}
Expand Down
19 changes: 12 additions & 7 deletions lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,9 @@ ParserResult<Expr> Parser::parseExprArrow() {
SourceLoc asyncLoc, throwsLoc, arrowLoc;
ParserStatus status;

status |= parseEffectsSpecifiers(SourceLoc(), asyncLoc, throwsLoc,
/*rethrows=*/nullptr);
status |= parseEffectsSpecifiers(SourceLoc(),
asyncLoc, /*reasync=*/nullptr,
throwsLoc, /*rethrows=*/nullptr);
if (status.hasCodeCompletion() && !CodeCompletion) {
// Trigger delayed parsing, no need to continue.
return status;
Expand All @@ -145,7 +146,9 @@ ParserResult<Expr> Parser::parseExprArrow() {

arrowLoc = consumeToken(tok::arrow);

parseEffectsSpecifiers(arrowLoc, asyncLoc, throwsLoc, /*rethrows=*/nullptr);
parseEffectsSpecifiers(arrowLoc,
asyncLoc, /*reasync=*/nullptr,
throwsLoc, /*rethrows=*/nullptr);

auto arrow = new (Context) ArrowExpr(asyncLoc, throwsLoc, arrowLoc);
return makeParserResult(arrow);
Expand Down Expand Up @@ -2600,8 +2603,9 @@ ParserStatus Parser::parseClosureSignatureIfPresent(
params = ParameterList::create(Context, elements);
}

status |= parseEffectsSpecifiers(SourceLoc(), asyncLoc, throwsLoc,
/*rethrows*/nullptr);
status |= parseEffectsSpecifiers(SourceLoc(),
asyncLoc, /*reasync*/nullptr,
throwsLoc, /*rethrows*/nullptr);

// Parse the optional explicit return type.
if (Tok.is(tok::arrow)) {
Expand All @@ -2620,8 +2624,9 @@ ParserStatus Parser::parseClosureSignatureIfPresent(
explicitResultType = new (Context) TypeExpr(explicitResultTypeRepr);

// Check for 'throws' and 'rethrows' after the type and correct it.
parseEffectsSpecifiers(arrowLoc, asyncLoc, throwsLoc,
/*rethrows*/nullptr);
parseEffectsSpecifiers(arrowLoc,
asyncLoc, /*reasync*/nullptr,
throwsLoc, /*rethrows*/nullptr);
}
}
}
Expand Down
48 changes: 33 additions & 15 deletions lib/Parse/ParsePattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ Parser::parseFunctionArguments(SmallVectorImpl<Identifier> &NamePieces,

/// Parse a function definition signature.
/// func-signature:
/// func-arguments 'async'? func-throws? func-signature-result?
/// func-arguments ('async'|'reasync')? func-throws? func-signature-result?
/// func-signature-result:
/// '->' type
///
Expand All @@ -772,6 +772,7 @@ Parser::parseFunctionSignature(Identifier SimpleName,
ParameterList *&bodyParams,
DefaultArgumentInfo &defaultArgs,
SourceLoc &asyncLoc,
bool &reasync,
SourceLoc &throwsLoc,
bool &rethrows,
TypeRepr *&retType) {
Expand All @@ -786,8 +787,11 @@ Parser::parseFunctionSignature(Identifier SimpleName,
FullName = DeclName(Context, SimpleName, NamePieces);

// Check for the 'async' and 'throws' keywords.
reasync = false;
rethrows = false;
Status |= parseEffectsSpecifiers(SourceLoc(), asyncLoc, throwsLoc, &rethrows);
Status |= parseEffectsSpecifiers(SourceLoc(),
asyncLoc, &reasync,
throwsLoc, &rethrows);

// If there's a trailing arrow, parse the rest as the result type.
SourceLoc arrowLoc;
Expand All @@ -800,9 +804,9 @@ Parser::parseFunctionSignature(Identifier SimpleName,
arrowLoc = consumeToken(tok::colon);
}

// Check for 'throws' and 'rethrows' after the arrow, but
// before the type, and correct it.
parseEffectsSpecifiers(arrowLoc, asyncLoc, throwsLoc, &rethrows);
// Check for effect specifiers after the arrow, but before the type, and
// correct it.
parseEffectsSpecifiers(arrowLoc, asyncLoc, &reasync, throwsLoc, &rethrows);

ParserResult<TypeRepr> ResultType =
parseDeclResultType(diag::expected_type_function_result);
Expand All @@ -811,8 +815,8 @@ Parser::parseFunctionSignature(Identifier SimpleName,
if (Status.isErrorOrHasCompletion())
return Status;

// Check for 'throws' and 'rethrows' after the type and correct it.
parseEffectsSpecifiers(arrowLoc, asyncLoc, throwsLoc, &rethrows);
// Check for effect specifiers after the type and correct it.
parseEffectsSpecifiers(arrowLoc, asyncLoc, &reasync, throwsLoc, &rethrows);
} else {
// Otherwise, we leave retType null.
retType = nullptr;
Expand All @@ -825,7 +829,8 @@ bool Parser::isEffectsSpecifier(const Token &T) {
// NOTE: If this returns 'true', that token must be handled in
// 'parseEffectsSpecifiers()'.

if (T.isContextualKeyword("async"))
if (T.isContextualKeyword("async") ||
T.isContextualKeyword("reasync"))
return true;

if (T.isAny(tok::kw_throws, tok::kw_rethrows) ||
Expand All @@ -837,35 +842,48 @@ bool Parser::isEffectsSpecifier(const Token &T) {

ParserStatus Parser::parseEffectsSpecifiers(SourceLoc existingArrowLoc,
SourceLoc &asyncLoc,
bool *reasync,
SourceLoc &throwsLoc,
bool *rethrows) {
ParserStatus status;

while (true) {
// 'async'
if (Tok.isContextualKeyword("async")) {

bool isReasync = Tok.isContextualKeyword("reasync");
if (Tok.isContextualKeyword("async") ||
isReasync) {
if (asyncLoc.isValid()) {
diagnose(Tok, diag::duplicate_effects_specifier, Tok.getText())
.highlight(asyncLoc)
.fixItRemove(Tok.getLoc());
} else if (!reasync && isReasync) {
// Replace 'reasync' with 'async' unless it's allowed.
diagnose(Tok, diag::reasync_function_type)
.fixItReplace(Tok.getLoc(), "async");
} else if (existingArrowLoc.isValid()) {
SourceLoc insertLoc = existingArrowLoc;
if (throwsLoc.isValid() &&
SourceMgr.isBeforeInBuffer(throwsLoc, insertLoc))
insertLoc = throwsLoc;
diagnose(Tok, diag::async_or_throws_in_wrong_position, "async")
diagnose(Tok, diag::async_or_throws_in_wrong_position,
(reasync && isReasync) ? "reasync" : "async")
.fixItRemove(Tok.getLoc())
.fixItInsert(insertLoc, "async ");
.fixItInsert(insertLoc,
(reasync && isReasync) ? "reasync " : "async ");
} else if (throwsLoc.isValid()) {
// 'async' cannot be after 'throws'.
assert(existingArrowLoc.isInvalid());
diagnose(Tok, diag::async_after_throws, rethrows && *rethrows)
diagnose(Tok, diag::async_after_throws,
reasync && isReasync,
rethrows && *rethrows)
.fixItRemove(Tok.getLoc())
.fixItInsert(throwsLoc, "async ");
.fixItInsert(throwsLoc, isReasync ? "reasync " : "async ");
}
if (asyncLoc.isInvalid())
if (asyncLoc.isInvalid()) {
if (reasync)
*reasync = isReasync;
asyncLoc = Tok.getLoc();
}
consumeToken();
continue;
}
Expand Down
9 changes: 6 additions & 3 deletions lib/Parse/ParseType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,16 +371,19 @@ ParserResult<TypeRepr> Parser::parseType(Diag<> MessageID,
SourceLoc asyncLoc;
SourceLoc throwsLoc;
if (isAtFunctionTypeArrow()) {
status |= parseEffectsSpecifiers(SourceLoc(), asyncLoc, throwsLoc,
/*rethrows=*/nullptr);
status |= parseEffectsSpecifiers(SourceLoc(),
asyncLoc, /*reasync=*/nullptr,
throwsLoc, /*rethrows=*/nullptr);
}

// Handle type-function if we have an arrow.
if (Tok.is(tok::arrow)) {
SourceLoc arrowLoc = consumeToken();

// Handle async/throws in the wrong place.
parseEffectsSpecifiers(arrowLoc, asyncLoc, throwsLoc, /*rethrows=*/nullptr);
parseEffectsSpecifiers(arrowLoc,
asyncLoc, /*reasync=*/nullptr,
throwsLoc, /*rethrows=*/nullptr);

ParserResult<TypeRepr> SecondHalf =
parseType(diag::expected_type_function_result);
Expand Down
Loading