Skip to content

Commit b4fb4a0

Browse files
authored
Merge pull request #33199 from DougGregor/concurrency-await
[Concurrency] Implement parsing and semantic analysis of await operator
2 parents 27c3a7b + 8bde04c commit b4fb4a0

File tree

14 files changed

+280
-108
lines changed

14 files changed

+280
-108
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,10 @@ ERROR(expected_colon_after_if_question,none,
12561256
"expected ':' after '? ...' in ternary expression", ())
12571257
ERROR(expected_expr_after_if_colon,none,
12581258
"expected expression after '? ... :' in ternary expression", ())
1259+
ERROR(expected_expr_after_try, none,
1260+
"expected expression after 'try'", ())
1261+
ERROR(expected_expr_after_await, none,
1262+
"expected expression after 'await'", ())
12591263

12601264
// Cast expressions
12611265
ERROR(expected_type_after_is,none,

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3320,7 +3320,7 @@ ERROR(missing_builtin_precedence_group,none,
33203320
(Identifier))
33213321

33223322
// If you change this, also change enum TryKindForDiagnostics.
3323-
#define TRY_KIND_SELECT(SUB) "%select{try|try!|try?}" #SUB
3323+
#define TRY_KIND_SELECT(SUB) "%select{try|try!|try?|await}" #SUB
33243324

33253325
ERROR(try_rhs,none,
33263326
"'" TRY_KIND_SELECT(0) "' cannot appear to the right of a "
@@ -4019,6 +4019,10 @@ NOTE(note_error_to_optional,none,
40194019
"did you mean to handle error as optional value?", ())
40204020
NOTE(note_disable_error_propagation,none,
40214021
"did you mean to disable error propagation?", ())
4022+
ERROR(async_call_without_await,none,
4023+
"call is 'async' but is not marked with 'await'", ())
4024+
WARNING(no_async_in_await,none,
4025+
"no calls to 'async' functions occur within 'await' expression", ())
40224026

40234027
WARNING(no_throw_in_try,none,
40244028
"no calls to throwing functions occur within 'try' expression", ())

include/swift/AST/Expr.h

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,7 +1964,7 @@ class TryExpr : public AnyTryExpr {
19641964
/// ForceTryExpr - A 'try!' surrounding an expression, marking that
19651965
/// the expression contains code which might throw, but that the code
19661966
/// should dynamically assert if it does.
1967-
class ForceTryExpr : public AnyTryExpr {
1967+
class ForceTryExpr final : public AnyTryExpr {
19681968
SourceLoc ExclaimLoc;
19691969

19701970
public:
@@ -1983,7 +1983,7 @@ class ForceTryExpr : public AnyTryExpr {
19831983
/// A 'try?' surrounding an expression, marking that the expression contains
19841984
/// code which might throw, and that the result should be injected into an
19851985
/// Optional. If the code does throw, \c nil is produced.
1986-
class OptionalTryExpr : public AnyTryExpr {
1986+
class OptionalTryExpr final : public AnyTryExpr {
19871987
SourceLoc QuestionLoc;
19881988

19891989
public:
@@ -2002,7 +2002,6 @@ class OptionalTryExpr : public AnyTryExpr {
20022002
/// An expression node that does not affect the evaluation of its subexpression.
20032003
class IdentityExpr : public Expr {
20042004
Expr *SubExpr;
2005-
20062005
public:
20072006
IdentityExpr(ExprKind kind,
20082007
Expr *subExpr, Type ty = Type(),
@@ -2093,6 +2092,32 @@ class ParenExpr : public IdentityExpr {
20932092
static bool classof(const Expr *E) { return E->getKind() == ExprKind::Paren; }
20942093
};
20952094

2095+
/// AwaitExpr - An 'await' surrounding an expression, marking that the
2096+
/// expression contains code which is a coroutine that may block.
2097+
///
2098+
/// getSemanticsProvidingExpr() looks through this because it doesn't
2099+
/// provide the value and only very specific clients care where the
2100+
/// 'await' was written.
2101+
class AwaitExpr final : public IdentityExpr {
2102+
SourceLoc AwaitLoc;
2103+
public:
2104+
AwaitExpr(SourceLoc awaitLoc, Expr *sub, Type type = Type(),
2105+
bool implicit = false)
2106+
: IdentityExpr(ExprKind::Await, sub, type, implicit), AwaitLoc(awaitLoc) {
2107+
}
2108+
2109+
SourceLoc getLoc() const { return AwaitLoc; }
2110+
2111+
SourceLoc getAwaitLoc() const { return AwaitLoc; }
2112+
SourceLoc getStartLoc() const { return AwaitLoc; }
2113+
SourceLoc getEndLoc() const { return getSubExpr()->getEndLoc(); }
2114+
2115+
static bool classof(const Expr *e) {
2116+
return e->getKind() == ExprKind::Await;
2117+
}
2118+
};
2119+
2120+
20962121
/// TupleExpr - Parenthesized expressions like '(a: x+x)' and '(x, y, 4)'. Also
20972122
/// used to represent the operands to a binary operator. Note that
20982123
/// expressions like '(4)' are represented with a ParenExpr.
@@ -3691,6 +3716,9 @@ class AbstractClosureExpr : public DeclContext, public Expr {
36913716
/// Return whether this closure is throwing when fully applied.
36923717
bool isBodyThrowing() const;
36933718

3719+
/// \brief Return whether this closure is async when fully applied.
3720+
bool isBodyAsync() const;
3721+
36943722
/// Whether this closure consists of a single expression.
36953723
bool hasSingleExpressionBody() const;
36963724

include/swift/AST/ExprNodes.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ UNCHECKED_EXPR(Sequence, Expr)
103103
ABSTRACT_EXPR(Identity, Expr)
104104
EXPR(Paren, IdentityExpr)
105105
EXPR(DotSelf, IdentityExpr)
106-
EXPR_RANGE(Identity, Paren, DotSelf)
106+
EXPR(Await, IdentityExpr)
107+
EXPR_RANGE(Identity, Paren, Await)
107108
ABSTRACT_EXPR(AnyTry, Expr)
108109
EXPR(Try, AnyTryExpr)
109110
EXPR(ForceTry, AnyTryExpr)

lib/AST/ASTDumper.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2130,6 +2130,13 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
21302130
printRec(E->getSubExpr());
21312131
PrintWithColorRAII(OS, ParenthesisColor) << ')';
21322132
}
2133+
void visitAwaitExpr(AwaitExpr *E) {
2134+
printCommon(E, "await_expr");
2135+
OS << '\n';
2136+
printRec(E->getSubExpr());
2137+
PrintWithColorRAII(OS, ParenthesisColor) << ')';
2138+
}
2139+
21332140
void visitTupleExpr(TupleExpr *E) {
21342141
printCommon(E, "tuple_expr");
21352142
if (E->hasTrailingClosure())

lib/AST/Expr.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const {
289289
->getSubExpr()->getReferencedDecl(stopAtParenExpr);
290290

291291
PASS_THROUGH_REFERENCE(DotSelf, getSubExpr);
292+
PASS_THROUGH_REFERENCE(Await, getSubExpr);
292293
PASS_THROUGH_REFERENCE(Try, getSubExpr);
293294
PASS_THROUGH_REFERENCE(ForceTry, getSubExpr);
294295
PASS_THROUGH_REFERENCE(OptionalTry, getSubExpr);
@@ -623,6 +624,7 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const {
623624
case ExprKind::DynamicType:
624625
return true;
625626

627+
case ExprKind::Await:
626628
case ExprKind::Try:
627629
case ExprKind::ForceTry:
628630
case ExprKind::OptionalTry:
@@ -1929,10 +1931,17 @@ Type AbstractClosureExpr::getResultType(
19291931
bool AbstractClosureExpr::isBodyThrowing() const {
19301932
if (getType()->hasError())
19311933
return false;
1932-
1934+
19331935
return getType()->castTo<FunctionType>()->getExtInfo().throws();
19341936
}
19351937

1938+
bool AbstractClosureExpr::isBodyAsync() const {
1939+
if (getType()->hasError())
1940+
return false;
1941+
1942+
return getType()->castTo<FunctionType>()->getExtInfo().async();
1943+
}
1944+
19361945
bool AbstractClosureExpr::hasSingleExpressionBody() const {
19371946
if (auto closure = dyn_cast<ClosureExpr>(this))
19381947
return closure->hasSingleExpressionBody();
@@ -2485,3 +2494,4 @@ const UnifiedStatsReporter::TraceFormatter*
24852494
FrontendStatsTracer::getTraceFormatter<const Expr *>() {
24862495
return &TF;
24872496
}
2497+

lib/Parse/ParseExpr.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -379,9 +379,10 @@ ParserResult<Expr> Parser::parseExprSequence(Diag<> Message,
379379
/// parseExprSequenceElement
380380
///
381381
/// expr-sequence-element(Mode):
382-
/// 'try' expr-unary(Mode)
383-
/// 'try' '?' expr-unary(Mode)
384-
/// 'try' '!' expr-unary(Mode)
382+
/// '__await' expr-sequence-element(Mode)
383+
/// 'try' expr-sequence-element(Mode)
384+
/// 'try' '?' expr-sequence-element(Mode)
385+
/// 'try' '!' expr-sequence-element(Mode)
385386
/// expr-unary(Mode)
386387
///
387388
/// 'try' is not actually allowed at an arbitrary position of a
@@ -390,6 +391,19 @@ ParserResult<Expr> Parser::parseExprSequenceElement(Diag<> message,
390391
bool isExprBasic) {
391392
SyntaxParsingContext ElementContext(SyntaxContext,
392393
SyntaxContextKind::Expr);
394+
395+
if (Context.LangOpts.EnableExperimentalConcurrency &&
396+
Tok.is(tok::kw___await)) {
397+
SourceLoc awaitLoc = consumeToken(tok::kw___await);
398+
ParserResult<Expr> sub = parseExprUnary(message, isExprBasic);
399+
if (!sub.hasCodeCompletion() && !sub.isNull()) {
400+
ElementContext.setCreateSyntax(SyntaxKind::TryExpr);
401+
sub = makeParserResult(new (Context) AwaitExpr(awaitLoc, sub.get()));
402+
}
403+
404+
return sub;
405+
}
406+
393407
SourceLoc tryLoc;
394408
bool hadTry = consumeIf(tok::kw_try, tryLoc);
395409
Optional<Token> trySuffix;

lib/Parse/ParseStmt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ bool Parser::isStartOfStmt() {
7171

7272
case tok::kw_try: {
7373
// "try" cannot actually start any statements, but we parse it there for
74-
// better recovery.
74+
// better recovery in cases like 'try return'.
7575
Parser::BacktrackingScope backtrack(*this);
7676
consumeToken(tok::kw_try);
7777
return isStartOfStmt();

0 commit comments

Comments
 (0)