Skip to content

Commit a2e95eb

Browse files
James BrownJames Brown
authored andcommitted
issue #65913 - Correct wrong insertion point suggestion when using shorthand optional binding by looking for implicitDeclRefExpr that is optional and points to a VarDecl. If we have that, get the name and insert with fixItInsertAfter instead of fixItInsert.
1 parent 104ee13 commit a2e95eb

File tree

2 files changed

+70
-6
lines changed

2 files changed

+70
-6
lines changed

lib/Sema/TypeCheckEffects.cpp

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3558,7 +3558,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
35583558
Ctx.Diags.diagnose(E->getAwaitLoc(), diag::no_async_in_await);
35593559
}
35603560

3561-
void diagnoseUncoveredAsyncSite(const Expr *anchor) const {
3561+
void diagnoseUncoveredAsyncSite(Expr *anchor) const {
35623562
auto asyncPointIter = uncoveredAsync.find(anchor);
35633563
if (asyncPointIter == uncoveredAsync.end())
35643564
return;
@@ -3570,16 +3570,40 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
35703570
if (const AnyTryExpr *tryExpr = dyn_cast<AnyTryExpr>(autoClosure->getSingleExpressionBody()))
35713571
awaitInsertLoc = tryExpr->getSubExpr()->getStartLoc();
35723572
}
3573+
3574+
auto shorthandOptionalBinding = [&](Expr *anchor) -> VarDecl * {
3575+
VarDecl *varDecl = nullptr;
3576+
if (!anchor->getType()->isOptional())
3577+
return nullptr;
3578+
anchor->forEachChildExpr([&](Expr *expr) -> Expr * {
3579+
if (auto *declRef = dyn_cast<DeclRefExpr>(expr)) {
3580+
if (declRef && declRef->isImplicit()) {
3581+
varDecl = dyn_cast<VarDecl>(declRef->getDecl());
3582+
return nullptr;
3583+
}
3584+
}
3585+
return expr;
3586+
});
3587+
return varDecl;
3588+
};
35733589

35743590
bool downgradeToWarning = llvm::all_of(errors,
35753591
[&](DiagnosticInfo diag) -> bool {
35763592
return diag.downgradeToWarning;
35773593
});
3578-
3579-
Ctx.Diags.diagnose(anchor->getStartLoc(), diag::async_expr_without_await)
3580-
.warnUntilSwiftVersionIf(downgradeToWarning, 6)
3581-
.fixItInsert(awaitInsertLoc, "await ")
3582-
.highlight(anchor->getSourceRange());
3594+
3595+
if (auto varDecl = shorthandOptionalBinding(anchor)) {
3596+
Ctx.Diags.diagnose(anchor->getStartLoc(), diag::async_expr_without_await)
3597+
.warnUntilSwiftVersionIf(downgradeToWarning, 6)
3598+
.fixItInsertAfter(anchor->getStartLoc(),
3599+
(" = await " + varDecl->getName().str()).str())
3600+
.highlight(anchor->getSourceRange());
3601+
} else {
3602+
Ctx.Diags.diagnose(anchor->getStartLoc(), diag::async_expr_without_await)
3603+
.warnUntilSwiftVersionIf(downgradeToWarning, 6)
3604+
.fixItInsert(awaitInsertLoc, "await ")
3605+
.highlight(anchor->getSourceRange());
3606+
}
35833607

35843608
for (const DiagnosticInfo &diag: errors) {
35853609
switch (diag.reason.getKind()) {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking
2+
3+
// REQUIRES: concurrency
4+
class A {}
5+
class B: A {}
6+
typealias Foo = (name: String, age: Int)
7+
func test() async {
8+
async let result: B? = nil
9+
async let person: Foo? = nil
10+
if let result: A = result {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{22-22=await }}
11+
// expected-warning@-1 {{immutable value 'result' was never used; consider replacing with '_' or removing it}}
12+
// expected-note@-2 {{reference to async let 'result' is 'async'}}
13+
if let result: A {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{19-19= = await result}}
14+
// expected-warning@-1 {{immutable value 'result' was never used; consider replacing with '_' or removing it}}
15+
// expected-note@-2 {{reference to async let 'result' is 'async'}}
16+
if let result = result {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{19-19=await }}
17+
// expected-warning@-1 {{value 'result' was defined but never used; consider replacing with boolean test}}
18+
// expected-note@-2 {{reference to async let 'result' is 'async'}}
19+
if let result {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{16-16= = await result}}
20+
// expected-warning@-1 {{value 'result' was defined but never used; consider replacing with boolean test}}
21+
// expected-note@-2 {{reference to async let 'result' is 'async'}}
22+
if let person: Foo = person {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{24-24=await }}
23+
// expected-warning@-1 {{immutable value 'person' was never used; consider replacing with '_' or removing it}}
24+
// expected-note@-2 {{reference to async let 'person' is 'async'}}
25+
if let person: Foo {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{21-21= = await person}}
26+
// expected-warning@-1 {{immutable value 'person' was never used; consider replacing with '_' or removing it}}
27+
// expected-note@-2 {{reference to async let 'person' is 'async'}}
28+
if let person: (String, Int) = person {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{34-34=await }}
29+
// expected-warning@-1 {{immutable value 'person' was never used; consider replacing with '_' or removing it}}
30+
// expected-note@-2 {{reference to async let 'person' is 'async'}}
31+
if let person: (String, Int) {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{31-31= = await person}}
32+
// expected-warning@-1 {{immutable value 'person' was never used; consider replacing with '_' or removing it}}
33+
// expected-note@-2 {{reference to async let 'person' is 'async'}}
34+
if let person = person {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{19-19=await }}
35+
// expected-warning@-1 {{value 'person' was defined but never used; consider replacing with boolean test}}
36+
// expected-note@-2 {{reference to async let 'person' is 'async'}}
37+
if let person {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{16-16= = await person}}
38+
// expected-warning@-1 {{value 'person' was defined but never used; consider replacing with boolean test}}
39+
// expected-note@-2 {{reference to async let 'person' is 'async'}}
40+
}

0 commit comments

Comments
 (0)