Skip to content

Commit 2eda5b7

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 3990e17 commit 2eda5b7

File tree

2 files changed

+72
-6
lines changed

2 files changed

+72
-6
lines changed

lib/Sema/TypeCheckEffects.cpp

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3581,7 +3581,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
35813581
Ctx.Diags.diagnose(E->getAwaitLoc(), diag::no_async_in_await);
35823582
}
35833583

3584-
void diagnoseUncoveredAsyncSite(const Expr *anchor) const {
3584+
void diagnoseUncoveredAsyncSite(Expr *anchor) const {
35853585
auto asyncPointIter = uncoveredAsync.find(anchor);
35863586
if (asyncPointIter == uncoveredAsync.end())
35873587
return;
@@ -3593,16 +3593,38 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
35933593
if (const AnyTryExpr *tryExpr = dyn_cast<AnyTryExpr>(autoClosure->getSingleExpressionBody()))
35943594
awaitInsertLoc = tryExpr->getSubExpr()->getStartLoc();
35953595
}
3596+
3597+
auto findShorthandOptionalBinding = [&](Expr *anchor) -> VarDecl * {
3598+
VarDecl *varDecl = nullptr;
3599+
if (!anchor->getType()->isOptional())
3600+
return nullptr;
3601+
anchor->forEachChildExpr([&](Expr *expr) -> Expr * {
3602+
if (isa<DeclRefExpr>(expr) && expr->isImplicit()) {
3603+
varDecl = dyn_cast<VarDecl>(expr->getReferencedDecl().getDecl());
3604+
return nullptr;
3605+
}
3606+
return expr;
3607+
});
3608+
return varDecl;
3609+
};
35963610

35973611
bool downgradeToWarning = llvm::all_of(errors,
35983612
[&](DiagnosticInfo diag) -> bool {
35993613
return diag.downgradeToWarning;
36003614
});
3601-
3602-
Ctx.Diags.diagnose(anchor->getStartLoc(), diag::async_expr_without_await)
3603-
.warnUntilSwiftVersionIf(downgradeToWarning, 6)
3604-
.fixItInsert(awaitInsertLoc, "await ")
3605-
.highlight(anchor->getSourceRange());
3615+
3616+
if (auto *varDecl = findShorthandOptionalBinding(anchor)) {
3617+
Ctx.Diags.diagnose(anchor->getStartLoc(), diag::async_expr_without_await)
3618+
.warnUntilSwiftVersionIf(downgradeToWarning, 6)
3619+
.fixItInsertAfter(anchor->getStartLoc(),
3620+
" = await " + varDecl->getNameStr().str())
3621+
.highlight(anchor->getSourceRange());
3622+
} else {
3623+
Ctx.Diags.diagnose(anchor->getStartLoc(), diag::async_expr_without_await)
3624+
.warnUntilSwiftVersionIf(downgradeToWarning, 6)
3625+
.fixItInsert(awaitInsertLoc, "await ")
3626+
.highlight(anchor->getSourceRange());
3627+
}
36063628

36073629
for (const DiagnosticInfo &diag: errors) {
36083630
switch (diag.reason.getKind()) {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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 f(_ x: String) async -> String? { x }
8+
func test() async {
9+
async let result: B? = nil
10+
async let person: Foo? = nil
11+
if let result: A = result {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{22-22=await }}
12+
// expected-warning@-1 {{immutable value 'result' was never used; consider replacing with '_' or removing it}}
13+
// expected-note@-2 {{reference to async let 'result' is 'async'}}
14+
if let result: A {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{19-19= = await result}}
15+
// expected-warning@-1 {{immutable value 'result' was never used; consider replacing with '_' or removing it}}
16+
// expected-note@-2 {{reference to async let 'result' is 'async'}}
17+
if let result = result {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{19-19=await }}
18+
// expected-warning@-1 {{value 'result' was defined but never used; consider replacing with boolean test}}
19+
// expected-note@-2 {{reference to async let 'result' is 'async'}}
20+
if let result {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{16-16= = await result}}
21+
// expected-warning@-1 {{value 'result' was defined but never used; consider replacing with boolean test}}
22+
// expected-note@-2 {{reference to async let 'result' is 'async'}}
23+
if let person: Foo = person {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{24-24=await }}
24+
// expected-warning@-1 {{immutable value 'person' was never used; consider replacing with '_' or removing it}}
25+
// expected-note@-2 {{reference to async let 'person' is 'async'}}
26+
if let person: Foo {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{21-21= = await person}}
27+
// expected-warning@-1 {{immutable value 'person' was never used; consider replacing with '_' or removing it}}
28+
// expected-note@-2 {{reference to async let 'person' is 'async'}}
29+
if let person: (String, Int) = person {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{34-34=await }}
30+
// expected-warning@-1 {{immutable value 'person' was never used; consider replacing with '_' or removing it}}
31+
// expected-note@-2 {{reference to async let 'person' is 'async'}}
32+
if let person: (String, Int) {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{31-31= = await person}}
33+
// expected-warning@-1 {{immutable value 'person' was never used; consider replacing with '_' or removing it}}
34+
// expected-note@-2 {{reference to async let 'person' is 'async'}}
35+
if let person = person {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{19-19=await }}
36+
// expected-warning@-1 {{value 'person' was defined but never used; consider replacing with boolean test}}
37+
// expected-note@-2 {{reference to async let 'person' is 'async'}}
38+
if let person {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{16-16= = await person}}
39+
// expected-warning@-1 {{value 'person' was defined but never used; consider replacing with boolean test}}
40+
// expected-note@-2 {{reference to async let 'person' is 'async'}}
41+
let a = f("a") // expected-error {{expression is 'async' but is not marked with 'await'}} {{11-11=await }}
42+
// expected-warning@-1 {{initialization of immutable value 'a' was never used; consider replacing with assignment to '_' or removing it}}
43+
// expected-note@-2 {{call is 'async'}}
44+
}

0 commit comments

Comments
 (0)