Skip to content

Commit 59a218a

Browse files
authored
Merge pull request #36763 from etcwilde/ewilde/fix-try-await-fix-it
[Concurrency] Fix try-await fix-it
2 parents 0d6f7e2 + 45c81c2 commit 59a218a

File tree

2 files changed

+23
-11
lines changed

2 files changed

+23
-11
lines changed

lib/Sema/TypeCheckEffects.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,6 +1425,9 @@ class Context {
14251425
DiagnoseErrorOnTry = b;
14261426
}
14271427

1428+
/// Stores the location of the innermost await
1429+
SourceLoc awaitLoc = SourceLoc();
1430+
14281431
/// Whether this is a function that rethrows.
14291432
bool hasPolymorphicEffect(EffectKind kind) const {
14301433
if (!Function)
@@ -1684,7 +1687,7 @@ class Context {
16841687
auto loc = E.getStartLoc();
16851688
SourceLoc insertLoc;
16861689
SourceRange highlight;
1687-
1690+
16881691
// Generate more specific messages in some cases.
16891692
if (auto e = dyn_cast_or_null<ApplyExpr>(E.dyn_cast<Expr*>())) {
16901693
if (isa<PrefixUnaryExpr>(e) || isa<PostfixUnaryExpr>(e) ||
@@ -1694,7 +1697,7 @@ class Context {
16941697
}
16951698
insertLoc = loc;
16961699
highlight = e->getSourceRange();
1697-
1700+
16981701
if (InterpolatedString &&
16991702
e->getCalledValue() &&
17001703
e->getCalledValue()->getBaseName() ==
@@ -1703,7 +1706,7 @@ class Context {
17031706
insertLoc = InterpolatedString->getLoc();
17041707
}
17051708
}
1706-
1709+
17071710
Diags.diagnose(loc, message).highlight(highlight);
17081711
maybeAddRethrowsNote(Diags, loc, reason);
17091712

@@ -1717,6 +1720,10 @@ class Context {
17171720
if (!suggestTryFixIt)
17181721
return;
17191722

1723+
// 'try' should go before 'await'
1724+
if (awaitLoc.isValid())
1725+
insertLoc = awaitLoc;
1726+
17201727
Diags.diagnose(loc, diag::note_forgot_try)
17211728
.fixItInsert(insertLoc, "try ");
17221729
Diags.diagnose(loc, diag::note_error_to_optional)
@@ -2116,14 +2123,16 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
21162123
DeclContext *OldReasyncDC;
21172124
ContextFlags OldFlags;
21182125
ConditionalEffectKind OldMaxThrowingKind;
2126+
SourceLoc OldAwaitLoc;
21192127

21202128
public:
21212129
ContextScope(CheckEffectsCoverage &self, Optional<Context> newContext)
21222130
: Self(self), OldContext(self.CurContext),
21232131
OldRethrowsDC(self.RethrowsDC),
21242132
OldReasyncDC(self.ReasyncDC),
21252133
OldFlags(self.Flags),
2126-
OldMaxThrowingKind(self.MaxThrowingKind) {
2134+
OldMaxThrowingKind(self.MaxThrowingKind),
2135+
OldAwaitLoc(self.CurContext.awaitLoc) {
21272136
if (newContext) self.CurContext = *newContext;
21282137
}
21292138

@@ -2141,9 +2150,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
21412150
Self.Flags.clear(ContextFlags::HasTryThrowSite);
21422151
}
21432152

2144-
void enterAwait() {
2153+
void enterAwait(SourceLoc awaitLoc) {
21452154
Self.Flags.set(ContextFlags::IsAsyncCovered);
21462155
Self.Flags.clear(ContextFlags::HasAnyAsyncSite);
2156+
Self.CurContext.awaitLoc = awaitLoc;
21472157
}
21482158

21492159
void enterAsyncLet() {
@@ -2240,6 +2250,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
22402250
Self.ReasyncDC = OldReasyncDC;
22412251
Self.Flags = OldFlags;
22422252
Self.MaxThrowingKind = OldMaxThrowingKind;
2253+
Self.CurContext.awaitLoc = OldAwaitLoc;
22432254
}
22442255
};
22452256

@@ -2648,12 +2659,13 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
26482659
break;
26492660
}
26502661
}
2662+
26512663
ShouldRecurse_t checkAwait(AwaitExpr *E) {
26522664

26532665
// Walk the operand.
26542666
ContextScope scope(*this, None);
2655-
scope.enterAwait();
2656-
2667+
scope.enterAwait(E->getAwaitLoc());
2668+
26572669
E->getSubExpr()->walk(*this);
26582670

26592671
// Warn about 'await' expressions that weren't actually needed, unless of
@@ -2666,7 +2678,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
26662678
CurContext.diagnoseUnhandledAsyncSite(Ctx.Diags, E, None,
26672679
/*forAwait=*/ true);
26682680
}
2669-
2681+
26702682
// Inform the parent of the walk that an 'await' exists here.
26712683
scope.preserveCoverageFromAwaitOperand();
26722684
return ShouldNotRecurse;

test/expr/unary/async_await.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@ func testThrowingAndAsync() async throws {
9999

100100
// Errors
101101
_ = await throwingAndAsync() // expected-error{{call can throw but is not marked with 'try'}}
102-
// expected-note@-1{{did you mean to use 'try'?}}
103-
// expected-note@-2{{did you mean to handle error as optional value?}}
104-
// expected-note@-3{{did you mean to disable error propagation?}}
102+
// expected-note@-1{{did you mean to use 'try'?}}{{7-7=try }}
103+
// expected-note@-2{{did you mean to handle error as optional value?}}{{7-7=try? }}
104+
// expected-note@-3{{did you mean to disable error propagation?}}{{7-7=try! }}
105105
_ = try throwingAndAsync() // expected-error{{call is 'async' but is not marked with 'await'}}{{11-11=await }}
106106
}
107107

0 commit comments

Comments
 (0)