Skip to content

Commit cc79dea

Browse files
committed
[TypeCheckEffects] Downgrade new effects checker errors on if/switch expressions
to warnings until Swift 6.
1 parent 9fc7032 commit cc79dea

File tree

4 files changed

+95
-74
lines changed

4 files changed

+95
-74
lines changed

lib/Sema/TypeCheckEffects.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2220,9 +2220,10 @@ class Context {
22202220
}
22212221

22222222
void diagnoseUncoveredThrowSite(ASTContext &ctx, ASTNode E,
2223-
const PotentialEffectReason &reason) {
2223+
const Classification &classification) {
22242224
auto &Diags = ctx.Diags;
22252225
auto message = diag::throwing_call_without_try;
2226+
const auto &reason = classification.getThrowReason();
22262227
auto reasonKind = reason.getKind();
22272228

22282229
bool suggestTryFixIt = reasonKind == PotentialEffectReason::Kind::Apply;
@@ -2262,7 +2263,8 @@ class Context {
22622263
}
22632264
}
22642265

2265-
Diags.diagnose(loc, message).highlight(highlight);
2266+
Diags.diagnose(loc, message).highlight(highlight)
2267+
.warnUntilSwiftVersionIf(classification.shouldDowngradeToWarning(), 6);
22662268
maybeAddRethrowsNote(Diags, loc, reason);
22672269

22682270
// If this is a call without expected 'try[?|!]', like this:
@@ -2565,6 +2567,12 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
25652567

25662568
/// Are we in an 'async let' initializer context?
25672569
InAsyncLet = 0x100,
2570+
2571+
/// Does an enclosing 'if' or 'switch' expr have a 'try'?
2572+
StmtExprCoversTry = 0x200,
2573+
2574+
/// Does an enclosing 'if' or 'switch' expr have an 'await'?
2575+
StmtExprCoversAwait = 0x400,
25682576
};
25692577
private:
25702578
unsigned Bits;
@@ -2732,6 +2740,9 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
27322740
Self.Flags.reset();
27332741
Self.MaxThrowingKind = ConditionalEffectKind::None;
27342742

2743+
Self.Flags.mergeFrom(ContextFlags::StmtExprCoversTry, OldFlags);
2744+
Self.Flags.mergeFrom(ContextFlags::StmtExprCoversAwait, OldFlags);
2745+
27352746
// Suppress 'try' coverage checking within a single level of
27362747
// do/catch in debugger functions.
27372748
if (OldFlags.has(ContextFlags::IsTopLevelDebuggerFunction))
@@ -2752,6 +2763,12 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
27522763
void setCoverageForSingleValueStmtExpr() {
27532764
resetCoverage();
27542765
Self.Flags.mergeFrom(ContextFlags::InAsyncLet, OldFlags);
2766+
2767+
if (OldFlags.has(ContextFlags::IsTryCovered))
2768+
Self.Flags.set(ContextFlags::StmtExprCoversTry);
2769+
2770+
if (OldFlags.has(ContextFlags::IsAsyncCovered))
2771+
Self.Flags.set(ContextFlags::StmtExprCoversAwait);
27552772
}
27562773

27572774
void preserveCoverageFromSingleValueStmtExpr() {
@@ -3152,7 +3169,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
31523169

31533170
ThrownErrorDestination
31543171
checkThrowAsyncSite(ASTNode E, bool requiresTry,
3155-
const Classification &classification) {
3172+
Classification &classification) {
31563173
// Suppress all diagnostics when there's an un-analyzable throw/async site.
31573174
if (classification.isInvalid()) {
31583175
Flags.set(ContextFlags::HasAnyThrowSite);
@@ -3185,6 +3202,8 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
31853202
Expr *expr = E.dyn_cast<Expr*>();
31863203
Expr *anchor = walkToAnchor(expr, parentMap,
31873204
CurContext.isWithinInterpolatedString());
3205+
if (Flags.has(ContextFlags::StmtExprCoversAwait))
3206+
classification.setDowngradeToWarning(true);
31883207
if (uncoveredAsync.find(anchor) == uncoveredAsync.end())
31893208
errorOrder.push_back(anchor);
31903209
uncoveredAsync[anchor].emplace_back(
@@ -3223,8 +3242,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
32233242
CurContext.diagnoseUnhandledThrowSite(Ctx.Diags, E, isTryCovered,
32243243
classification.getThrowReason());
32253244
} else if (!isTryCovered) {
3245+
if (Flags.has(ContextFlags::StmtExprCoversTry))
3246+
classification.setDowngradeToWarning(true);
32263247
CurContext.diagnoseUncoveredThrowSite(Ctx, E, // we want this one to trigger
3227-
classification.getThrowReason());
3248+
classification);
32283249
} else {
32293250
return checkThrownErrorType(
32303251
E.getStartLoc(), classification.getThrownError());

test/expr/unary/do_expr.swift

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ func tryDo4() throws -> Int {
155155
func tryDo5() throws -> Int {
156156
return try do { tryDo4() }
157157
// expected-warning@-1 {{'try' has no effect on 'do' expression}}
158-
// expected-error@-2 {{call can throw but is not marked with 'try'}}
158+
// expected-warning@-2 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
159159
// expected-note@-3 {{did you mean to use 'try'?}}
160160
// expected-note@-4 {{did you mean to handle error as optional value?}}
161161
// expected-note@-5 {{did you mean to disable error propagation?}}
@@ -164,7 +164,7 @@ func tryDo5() throws -> Int {
164164
func tryDo6() throws -> Int {
165165
try do { tryDo4() }
166166
// expected-warning@-1 {{'try' has no effect on 'do' expression}}
167-
// expected-error@-2 {{call can throw but is not marked with 'try'}}
167+
// expected-warning@-2 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
168168
// expected-note@-3 {{did you mean to use 'try'?}}
169169
// expected-note@-4 {{did you mean to handle error as optional value?}}
170170
// expected-note@-5 {{did you mean to disable error propagation?}}
@@ -173,7 +173,7 @@ func tryDo6() throws -> Int {
173173
func tryDo7() throws -> Int {
174174
let x = try do { tryDo4() }
175175
// expected-warning@-1 {{'try' has no effect on 'do' expression}}
176-
// expected-error@-2 {{call can throw but is not marked with 'try'}}
176+
// expected-warning@-2 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
177177
// expected-note@-3 {{did you mean to use 'try'?}}
178178
// expected-note@-4 {{did you mean to handle error as optional value?}}
179179
// expected-note@-5 {{did you mean to disable error propagation?}}
@@ -199,7 +199,7 @@ func tryDo10() throws -> Int {
199199
func tryDo11() throws -> Int {
200200
let x = try do { try tryDo4() } catch { tryDo4() }
201201
// expected-warning@-1 {{'try' has no effect on 'do-catch' expression}}
202-
// expected-error@-2 {{call can throw but is not marked with 'try'}}
202+
// expected-warning@-2 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
203203
// expected-note@-3 {{did you mean to use 'try'?}}
204204
// expected-note@-4 {{did you mean to handle error as optional value?}}
205205
// expected-note@-5 {{did you mean to disable error propagation?}}
@@ -209,7 +209,7 @@ func tryDo11() throws -> Int {
209209
func tryDo12() throws -> Int {
210210
let x = try do { tryDo4() } catch { tryDo4() }
211211
// expected-warning@-1 {{'try' has no effect on 'do-catch' expression}}
212-
// expected-error@-2 2{{call can throw but is not marked with 'try'}}
212+
// expected-warning@-2 2{{call can throw but is not marked with 'try'; this is an error in Swift 6}}
213213
// expected-note@-3 2{{did you mean to use 'try'?}}
214214
// expected-note@-4 2{{did you mean to handle error as optional value?}}
215215
// expected-note@-5 2{{did you mean to disable error propagation?}}
@@ -219,13 +219,13 @@ func tryDo12() throws -> Int {
219219
func tryDo13() throws -> Int {
220220
let x = try do { // expected-warning {{'try' has no effect on 'do-catch' expression}}
221221
tryDo4() // expected-warning {{result of call to 'tryDo4()' is unused}}
222-
// expected-error@-1 {{call can throw but is not marked with 'try'}}
222+
// expected-warning@-1 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
223223
// expected-note@-2 {{did you mean to use 'try'?}}
224224
// expected-note@-3 {{did you mean to handle error as optional value?}}
225225
// expected-note@-4 {{did you mean to disable error propagation?}}
226226

227227
_ = tryDo4()
228-
// expected-error@-1 {{call can throw but is not marked with 'try'}}
228+
// expected-warning@-1 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
229229
// expected-note@-2 {{did you mean to use 'try'?}}
230230
// expected-note@-3 {{did you mean to handle error as optional value?}}
231231
// expected-note@-4 {{did you mean to disable error propagation?}}
@@ -409,21 +409,21 @@ func awaitDo4() async -> Int {
409409
func awaitDo5() async -> Int {
410410
return await do { awaitDo4() }
411411
// expected-warning@-1 {{'await' has no effect on 'do' expression}}
412-
// expected-error@-2 {{expression is 'async' but is not marked with 'await'}}
412+
// expected-warning@-2 {{expression is 'async' but is not marked with 'await'}}
413413
// expected-note@-3 {{call is 'async'}}
414414
}
415415

416416
func awaitDo6() async -> Int {
417417
await do { awaitDo4() }
418418
// expected-warning@-1 {{'await' has no effect on 'do' expression}}
419-
// expected-error@-2 {{expression is 'async' but is not marked with 'await'}}
419+
// expected-warning@-2 {{expression is 'async' but is not marked with 'await'}}
420420
// expected-note@-3 {{call is 'async'}}
421421
}
422422

423423
func awaitDo7() async -> Int {
424424
let x = await do { awaitDo4() }
425425
// expected-warning@-1 {{'await' has no effect on 'do' expression}}
426-
// expected-error@-2 {{expression is 'async' but is not marked with 'await'}}
426+
// expected-warning@-2 {{expression is 'async' but is not marked with 'await'}}
427427
// expected-note@-3 {{call is 'async'}}
428428
return x
429429
}
@@ -447,27 +447,27 @@ func awaitDo10() async -> Int {
447447
func awaitDo11() async -> Int {
448448
let x = await do { try await tryAwaitDo1() } catch { awaitDo4() }
449449
// expected-warning@-1 {{'await' has no effect on 'do-catch' expression}}
450-
// expected-error@-2 {{expression is 'async' but is not marked with 'await'}}
450+
// expected-warning@-2 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
451451
// expected-note@-3 {{call is 'async'}}
452452
return x
453453
}
454454

455455
func awaitDo12() async -> Int {
456456
let x = await do { try tryAwaitDo1() } catch { awaitDo4() }
457457
// expected-warning@-1 {{'await' has no effect on 'do-catch' expression}}
458-
// expected-error@-2 2{{expression is 'async' but is not marked with 'await'}}
458+
// expected-warning@-2 2{{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
459459
// expected-note@-3 2{{call is 'async'}}
460460
return x
461461
}
462462

463463
func awaitDo13() async throws -> Int {
464464
let x = await do { // expected-warning {{'await' has no effect on 'do-catch' expression}}
465465
awaitDo4() // expected-warning {{result of call to 'awaitDo4()' is unused}}
466-
// expected-error@-1 {{expression is 'async' but is not marked with 'await'}}
466+
// expected-warning@-1 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
467467
// expected-note@-2 {{call is 'async'}}
468468

469469
_ = awaitDo4()
470-
// expected-error@-1 {{expression is 'async' but is not marked with 'await'}}
470+
// expected-warning@-1 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
471471
// expected-note@-2 {{call is 'async'}}
472472

473473
_ = await awaitDo4() // Okay.
@@ -543,27 +543,27 @@ func tryAwaitDo3() async throws -> Int {
543543
try await do { tryAwaitDo2() } as Int
544544
// expected-warning@-1 {{'try' has no effect on 'do' expression}}
545545
// expected-warning@-2 {{'await' has no effect on 'do' expression}}
546-
// expected-error@-3 {{call can throw but is not marked with 'try'}}
546+
// expected-warning@-3 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
547547
// expected-note@-4 {{did you mean to use 'try'?}}
548548
// expected-note@-5 {{did you mean to handle error as optional value?}}
549549
// expected-note@-6 {{did you mean to disable error propagation?}}
550-
// expected-error@-7 {{expression is 'async' but is not marked with 'await'}}
550+
// expected-warning@-7 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
551551
// expected-note@-8 {{call is 'async'}}
552552
}
553553

554554
func tryAwaitDo4() async throws -> Int {
555555
try await do { try tryAwaitDo2() } as Int
556556
// expected-warning@-1 {{'try' has no effect on 'do' expression}}
557557
// expected-warning@-2 {{'await' has no effect on 'do' expression}}
558-
// expected-error@-3 {{expression is 'async' but is not marked with 'await'}}
558+
// expected-warning@-3 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
559559
// expected-note@-4 {{call is 'async'}}
560560
}
561561

562562
func tryAwaitDo5() async throws -> Int {
563563
try await do { await tryAwaitDo2() } as Int
564564
// expected-warning@-1 {{'try' has no effect on 'do' expression}}
565565
// expected-warning@-2 {{'await' has no effect on 'do' expression}}
566-
// expected-error@-3 {{call can throw but is not marked with 'try'}}
566+
// expected-warning@-3 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
567567
// expected-note@-4 {{did you mean to use 'try'?}}
568568
// expected-note@-5 {{did you mean to handle error as optional value?}}
569569
// expected-note@-6 {{did you mean to disable error propagation?}}
@@ -579,27 +579,27 @@ func tryAwaitDo7() async throws -> Int {
579579
try await do { tryAwaitDo2() }
580580
// expected-warning@-1 {{'try' has no effect on 'do' expression}}
581581
// expected-warning@-2 {{'await' has no effect on 'do' expression}}
582-
// expected-error@-3 {{call can throw but is not marked with 'try'}}
582+
// expected-warning@-3 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
583583
// expected-note@-4 {{did you mean to use 'try'?}}
584584
// expected-note@-5 {{did you mean to handle error as optional value?}}
585585
// expected-note@-6 {{did you mean to disable error propagation?}}
586-
// expected-error@-7 {{expression is 'async' but is not marked with 'await'}}
586+
// expected-warning@-7 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
587587
// expected-note@-8 {{call is 'async'}}
588588
}
589589

590590
func tryAwaitDo8() async throws -> Int {
591591
try await do { try tryAwaitDo2() }
592592
// expected-warning@-1 {{'try' has no effect on 'do' expression}}
593593
// expected-warning@-2 {{'await' has no effect on 'do' expression}}
594-
// expected-error@-3 {{expression is 'async' but is not marked with 'await'}}
594+
// expected-warning@-3 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
595595
// expected-note@-4 {{call is 'async'}}
596596
}
597597

598598
func tryAwaitDo9() async throws -> Int {
599599
try await do { await tryAwaitDo2() }
600600
// expected-warning@-1 {{'try' has no effect on 'do' expression}}
601601
// expected-warning@-2 {{'await' has no effect on 'do' expression}}
602-
// expected-error@-3 {{call can throw but is not marked with 'try'}}
602+
// expected-warning@-3 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
603603
// expected-note@-4 {{did you mean to use 'try'?}}
604604
// expected-note@-5 {{did you mean to handle error as optional value?}}
605605
// expected-note@-6 {{did you mean to disable error propagation?}}

0 commit comments

Comments
 (0)