Skip to content

Commit dc4a119

Browse files
committed
[Concurrency] Diagnose 'async let' declarations in non-async contexts.
1 parent 9722df8 commit dc4a119

File tree

4 files changed

+41
-6
lines changed

4 files changed

+41
-6
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,6 +1784,9 @@ class PatternBindingDecl final : public Decl,
17841784
/// Is the pattern binding entry for this variable currently being computed?
17851785
bool isComputingPatternBindingEntry(const VarDecl *vd) const;
17861786

1787+
/// Is this an "async let" declaration.
1788+
bool isAsyncLet() const;
1789+
17871790
/// Gets the text of the initializer expression for the pattern entry at the
17881791
/// given index, stripping out inactive branches of any #ifs inside the
17891792
/// expression.

lib/AST/Decl.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,6 +1545,13 @@ StaticSpellingKind PatternBindingDecl::getCorrectStaticSpelling() const {
15451545
return getCorrectStaticSpellingForDecl(this);
15461546
}
15471547

1548+
bool PatternBindingDecl::isAsyncLet() const {
1549+
if (auto var = getAnchoringVarDecl(0))
1550+
return var->isAsyncLet();
1551+
1552+
return false;
1553+
}
1554+
15481555

15491556
bool PatternBindingDecl::hasStorage() const {
15501557
// Walk the pattern, to check to see if any of the VarDecls included in it

lib/Sema/TypeCheckEffects.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,14 @@ class EffectsHandlingWalker : public ASTWalker {
194194
ShouldRecurse_t recurse = ShouldRecurse;
195195
// Skip the implementations of all local declarations... except
196196
// PBD. We should really just have a PatternBindingStmt.
197-
if (auto ic = dyn_cast<IfConfigDecl>(D))
197+
if (auto ic = dyn_cast<IfConfigDecl>(D)) {
198198
recurse = asImpl().checkIfConfig(ic);
199-
else if (!isa<PatternBindingDecl>(D))
199+
} else if (auto patternBinding = dyn_cast<PatternBindingDecl>(D)) {
200+
if (patternBinding->isAsyncLet())
201+
recurse = asImpl().checkAsyncLet(patternBinding);
202+
} else {
200203
recurse = ShouldNotRecurse;
204+
}
201205
return bool(recurse);
202206
}
203207

@@ -661,6 +665,9 @@ class ApplyClassifier {
661665
ShouldRecurse_t checkDeclRef(DeclRefExpr *E) {
662666
return ShouldNotRecurse;
663667
}
668+
ShouldRecurse_t checkAsyncLet(PatternBindingDecl *patternBinding) {
669+
return ShouldRecurse;
670+
}
664671
ShouldRecurse_t checkThrow(ThrowStmt *E) {
665672
Result = ThrowingKind::Throws;
666673
return ShouldRecurse;
@@ -1321,6 +1328,15 @@ class Context {
13211328
}
13221329
}
13231330
}
1331+
} else if (auto patternBinding = dyn_cast_or_null<PatternBindingDecl>(
1332+
node.dyn_cast<Decl *>())) {
1333+
if (patternBinding->isAsyncLet()) {
1334+
auto var = patternBinding->getAnchoringVarDecl(0);
1335+
Diags.diagnose(
1336+
e->getLoc(), diag::async_let_in_illegal_context,
1337+
var->getName(), static_cast<unsigned>(getKind()));
1338+
return;
1339+
}
13241340
}
13251341

13261342
Diags.diagnose(node.getStartLoc(), diag::await_in_illegal_context,
@@ -1344,7 +1360,8 @@ class Context {
13441360
unsigned kind = 0;
13451361
if (node.isExpr(ExprKind::Await))
13461362
kind = 1;
1347-
else if (node.isExpr(ExprKind::DeclRef))
1363+
else if (node.isExpr(ExprKind::DeclRef) ||
1364+
node.isDecl(DeclKind::PatternBinding))
13481365
kind = 2;
13491366
Diags.diagnose(node.getStartLoc(), diag::async_in_nonasync_function,
13501367
kind, isAutoClosure());
@@ -1743,6 +1760,14 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
17431760
return ShouldNotRecurse;
17441761
}
17451762

1763+
ShouldRecurse_t checkAsyncLet(PatternBindingDecl *patternBinding) {
1764+
// Diagnose async calls in a context that doesn't handle async.
1765+
if (!CurContext.handlesAsync()) {
1766+
CurContext.diagnoseUnhandledAsyncSite(Ctx.Diags, patternBinding);
1767+
}
1768+
return ShouldRecurse;
1769+
}
1770+
17461771
ShouldRecurse_t
17471772
checkInterpolatedStringLiteral(InterpolatedStringLiteralExpr *E) {
17481773
ContextScope scope(*this, CurContext.withInterpolatedString(E));

test/expr/unary/async_await.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,10 @@ func testAsyncLet() async throws {
164164
}
165165
}
166166

167-
// expected-note@+2 2{{add 'async' to function 'testAsyncLetOutOfAsync()' to make it asynchronous}}
168-
// expected-note@+1 2{{add '@asyncHandler' to function 'testAsyncLetOutOfAsync()' to create an implicit asynchronous context}}
167+
// expected-note@+2 3{{add 'async' to function 'testAsyncLetOutOfAsync()' to make it asynchronous}}
168+
// expected-note@+1 3{{add '@asyncHandler' to function 'testAsyncLetOutOfAsync()' to create an implicit asynchronous context}}
169169
func testAsyncLetOutOfAsync() {
170-
async let x = 1 // ERROR?
170+
async let x = 1 // expected-error{{'async let' in a function that does not support concurrency}}
171171

172172
_ = await x // expected-error{{'async let' in a function that does not support concurrency}}
173173
_ = x // expected-error{{'async let' in a function that does not support concurrency}}

0 commit comments

Comments
 (0)