Skip to content

Commit 3ae93a9

Browse files
Merge pull request #72726 from Jamezzzb/issue-65913
2 parents f3d4969 + 5f8fec5 commit 3ae93a9

File tree

2 files changed

+48
-10
lines changed

2 files changed

+48
-10
lines changed

lib/Sema/TypeCheckEffects.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2809,7 +2809,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
28092809

28102810
static bool isEffectAnchor(Expr *e) {
28112811
return isa<AbstractClosureExpr>(e) || isa<DiscardAssignmentExpr>(e) ||
2812-
isa<AssignExpr>(e);
2812+
isa<AssignExpr>(e) || (isa<DeclRefExpr>(e) && e->isImplicit());
28132813
}
28142814

28152815
static bool isAnchorTooEarly(Expr *e) {
@@ -3589,27 +3589,43 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
35893589
Ctx.Diags.diagnose(E->getAwaitLoc(), diag::no_async_in_await);
35903590
}
35913591

3592-
void diagnoseUncoveredAsyncSite(const Expr *anchor) const {
3593-
auto asyncPointIter = uncoveredAsync.find(anchor);
3594-
if (asyncPointIter == uncoveredAsync.end())
3595-
return;
3596-
const std::vector<DiagnosticInfo> &errors = asyncPointIter->getSecond();
3592+
std::pair<SourceLoc, std::string>
3593+
getFixItForUncoveredAsyncSite(const Expr *anchor) const {
35973594
SourceLoc awaitInsertLoc = anchor->getStartLoc();
3598-
if (const AnyTryExpr *tryExpr = dyn_cast<AnyTryExpr>(anchor))
3595+
std::string insertText = "await ";
3596+
if (auto *tryExpr = dyn_cast<AnyTryExpr>(anchor))
35993597
awaitInsertLoc = tryExpr->getSubExpr()->getStartLoc();
3600-
else if (const AutoClosureExpr *autoClosure = dyn_cast<AutoClosureExpr>(anchor)) {
3601-
if (const AnyTryExpr *tryExpr = dyn_cast<AnyTryExpr>(autoClosure->getSingleExpressionBody()))
3598+
else if (auto *autoClosure = dyn_cast<AutoClosureExpr>(anchor)) {
3599+
if (auto *tryExpr =
3600+
dyn_cast<AnyTryExpr>(autoClosure->getSingleExpressionBody()))
36023601
awaitInsertLoc = tryExpr->getSubExpr()->getStartLoc();
3602+
// Supply a tailored fixIt including the identifier if we are
3603+
// looking at a shorthand optional binding.
3604+
} else if (anchor->isImplicit()) {
3605+
if (auto declRef = dyn_cast<DeclRefExpr>(anchor))
3606+
if (auto var = dyn_cast_or_null<VarDecl>(declRef->getDecl())) {
3607+
insertText = " = await " + var->getNameStr().str();
3608+
awaitInsertLoc = Lexer::getLocForEndOfToken(Ctx.Diags.SourceMgr,
3609+
anchor->getStartLoc());
3610+
}
36033611
}
3612+
return std::make_pair(awaitInsertLoc, insertText);
3613+
}
36043614

3615+
void diagnoseUncoveredAsyncSite(const Expr *anchor) const {
3616+
auto asyncPointIter = uncoveredAsync.find(anchor);
3617+
if (asyncPointIter == uncoveredAsync.end())
3618+
return;
3619+
const auto &errors = asyncPointIter->getSecond();
3620+
const auto &[loc, insertText] = getFixItForUncoveredAsyncSite(anchor);
36053621
bool downgradeToWarning = llvm::all_of(errors,
36063622
[&](DiagnosticInfo diag) -> bool {
36073623
return diag.downgradeToWarning;
36083624
});
36093625

36103626
Ctx.Diags.diagnose(anchor->getStartLoc(), diag::async_expr_without_await)
36113627
.warnUntilSwiftVersionIf(downgradeToWarning, 6)
3612-
.fixItInsert(awaitInsertLoc, "await ")
3628+
.fixItInsert(loc, insertText)
36133629
.highlight(anchor->getSourceRange());
36143630

36153631
for (const DiagnosticInfo &diag: errors) {

test/expr/unary/async_await.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,25 @@ func testAsyncLetOutOfAsync() {
217217
_ = await x // expected-error{{'async let' in a function that does not support concurrency}}
218218
_ = x // expected-error{{'async let' in a function that does not support concurrency}}
219219
}
220+
221+
class A {}
222+
class B: A {}
223+
func f(_ x: String) async -> String? { x }
224+
func testAsyncExprWithoutAwait() async {
225+
async let result: B? = nil
226+
if let result: A = result {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{22-22=await }}
227+
// expected-warning@-1 {{immutable value 'result' was never used; consider replacing with '_' or removing it}}
228+
// expected-note@-2 {{reference to async let 'result' is 'async'}}
229+
if let result: A {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{19-19= = await result}}
230+
// expected-warning@-1 {{immutable value 'result' was never used; consider replacing with '_' or removing it}}
231+
// expected-note@-2 {{reference to async let 'result' is 'async'}}
232+
if let result = result {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{19-19=await }}
233+
// expected-warning@-1 {{value 'result' was defined but never used; consider replacing with boolean test}}
234+
// expected-note@-2 {{reference to async let 'result' is 'async'}}
235+
if let result {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{16-16= = await result}}
236+
// expected-warning@-1 {{value 'result' was defined but never used; consider replacing with boolean test}}
237+
// expected-note@-2 {{reference to async let 'result' is 'async'}}
238+
let a = f("a") // expected-error {{expression is 'async' but is not marked with 'await'}} {{11-11=await }}
239+
// expected-warning@-1 {{initialization of immutable value 'a' was never used; consider replacing with assignment to '_' or removing it}}
240+
// expected-note@-2 {{call is 'async'}}
241+
}

0 commit comments

Comments
 (0)