Skip to content

Commit 5742388

Browse files
committed
[TypeCheckEffects] Downgrade new effects checker errors on if/switch expressions
to warnings until Swift 6. (cherry picked from commit cc79dea)
1 parent 9315ad1 commit 5742388

File tree

3 files changed

+81
-60
lines changed

3 files changed

+81
-60
lines changed

lib/Sema/TypeCheckEffects.cpp

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1709,9 +1709,10 @@ class Context {
17091709
}
17101710

17111711
void diagnoseUncoveredThrowSite(ASTContext &ctx, ASTNode E,
1712-
const PotentialEffectReason &reason) {
1712+
const Classification &classification) {
17131713
auto &Diags = ctx.Diags;
17141714
auto message = diag::throwing_call_without_try;
1715+
const auto &reason = classification.getThrowReason();
17151716
auto reasonKind = reason.getKind();
17161717

17171718
bool suggestTryFixIt = reasonKind == PotentialEffectReason::Kind::Apply;
@@ -1751,7 +1752,8 @@ class Context {
17511752
}
17521753
}
17531754

1754-
Diags.diagnose(loc, message).highlight(highlight);
1755+
Diags.diagnose(loc, message).highlight(highlight)
1756+
.warnUntilSwiftVersionIf(classification.shouldDowngradeToWarning(), 6);
17551757
maybeAddRethrowsNote(Diags, loc, reason);
17561758

17571759
// If this is a call without expected 'try[?|!]', like this:
@@ -2054,6 +2056,12 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
20542056

20552057
/// Are we in an 'async let' initializer context?
20562058
InAsyncLet = 0x100,
2059+
2060+
/// Does an enclosing 'if' or 'switch' expr have a 'try'?
2061+
StmtExprCoversTry = 0x200,
2062+
2063+
/// Does an enclosing 'if' or 'switch' expr have an 'await'?
2064+
StmtExprCoversAwait = 0x400,
20572065
};
20582066
private:
20592067
unsigned Bits;
@@ -2221,6 +2229,9 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
22212229
Self.Flags.reset();
22222230
Self.MaxThrowingKind = ConditionalEffectKind::None;
22232231

2232+
Self.Flags.mergeFrom(ContextFlags::StmtExprCoversTry, OldFlags);
2233+
Self.Flags.mergeFrom(ContextFlags::StmtExprCoversAwait, OldFlags);
2234+
22242235
// Suppress 'try' coverage checking within a single level of
22252236
// do/catch in debugger functions.
22262237
if (OldFlags.has(ContextFlags::IsTopLevelDebuggerFunction))
@@ -2241,6 +2252,12 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
22412252
void setCoverageForSingleValueStmtExpr() {
22422253
resetCoverage();
22432254
Self.Flags.mergeFrom(ContextFlags::InAsyncLet, OldFlags);
2255+
2256+
if (OldFlags.has(ContextFlags::IsTryCovered))
2257+
Self.Flags.set(ContextFlags::StmtExprCoversTry);
2258+
2259+
if (OldFlags.has(ContextFlags::IsAsyncCovered))
2260+
Self.Flags.set(ContextFlags::StmtExprCoversAwait);
22442261
}
22452262

22462263
void preserveCoverageFromSingleValueStmtExpr() {
@@ -2556,11 +2573,11 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
25562573
effects.push_back(EffectKind::Async);
25572574
}
25582575

2576+
auto classification = Classification::forEffect(effects,
2577+
ConditionalEffectKind::Always,
2578+
getKindOfEffectfulProp(member));
25592579
bool requiresTry = getter->hasThrows();
2560-
checkThrowAsyncSite(E, requiresTry,
2561-
Classification::forEffect(effects,
2562-
ConditionalEffectKind::Always,
2563-
getKindOfEffectfulProp(member)));
2580+
checkThrowAsyncSite(E, requiresTry, classification);
25642581

25652582
} else {
25662583
EffectList effects;
@@ -2600,10 +2617,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
26002617
effects.push_back(EffectKind::Async);
26012618
}
26022619

2603-
checkThrowAsyncSite(E, getter->hasThrows(),
2604-
Classification::forEffect(effects,
2605-
ConditionalEffectKind::Always,
2606-
PotentialEffectReason::forPropertyAccess()));
2620+
auto classification = Classification::forEffect(effects,
2621+
ConditionalEffectKind::Always,
2622+
PotentialEffectReason::forPropertyAccess());
2623+
checkThrowAsyncSite(E, getter->hasThrows(), classification);
26072624

26082625
} else if (E->isImplicitlyAsync()) {
26092626
auto classification = Classification::forUnconditional(
@@ -2713,7 +2730,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
27132730
}
27142731

27152732
void checkThrowAsyncSite(ASTNode E, bool requiresTry,
2716-
const Classification &classification) {
2733+
Classification &classification) {
27172734
// Suppress all diagnostics when there's an un-analyzable throw/async site.
27182735
if (classification.isInvalid()) {
27192736
Flags.set(ContextFlags::HasAnyThrowSite);
@@ -2746,6 +2763,8 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
27462763
Expr *expr = E.dyn_cast<Expr*>();
27472764
Expr *anchor = walkToAnchor(expr, parentMap,
27482765
CurContext.isWithinInterpolatedString());
2766+
if (Flags.has(ContextFlags::StmtExprCoversAwait))
2767+
classification.setDowngradeToWarning(true);
27492768
if (uncoveredAsync.find(anchor) == uncoveredAsync.end())
27502769
errorOrder.push_back(anchor);
27512770
uncoveredAsync[anchor].emplace_back(
@@ -2784,8 +2803,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
27842803
CurContext.diagnoseUnhandledThrowSite(Ctx.Diags, E, isTryCovered,
27852804
classification.getThrowReason());
27862805
} else if (!isTryCovered) {
2806+
if (Flags.has(ContextFlags::StmtExprCoversTry))
2807+
classification.setDowngradeToWarning(true);
27872808
CurContext.diagnoseUncoveredThrowSite(Ctx, E, // we want this one to trigger
2788-
classification.getThrowReason());
2809+
classification);
27892810
}
27902811
break;
27912812
}

test/expr/unary/if_expr.swift

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,7 +1010,7 @@ func tryIf4() throws -> Int {
10101010
func tryIf5() throws -> Int {
10111011
return try if .random() { tryIf4() } else { 1 }
10121012
// expected-warning@-1 {{'try' has no effect on 'if' expression}}
1013-
// expected-error@-2 {{call can throw but is not marked with 'try'}}
1013+
// expected-warning@-2 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
10141014
// expected-note@-3 {{did you mean to use 'try'?}}
10151015
// expected-note@-4 {{did you mean to handle error as optional value?}}
10161016
// expected-note@-5 {{did you mean to disable error propagation?}}
@@ -1019,7 +1019,7 @@ func tryIf5() throws -> Int {
10191019
func tryIf6() throws -> Int {
10201020
try if .random() { tryIf4() } else { 1 }
10211021
// expected-warning@-1 {{'try' has no effect on 'if' expression}}
1022-
// expected-error@-2 {{call can throw but is not marked with 'try'}}
1022+
// expected-warning@-2 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
10231023
// expected-note@-3 {{did you mean to use 'try'?}}
10241024
// expected-note@-4 {{did you mean to handle error as optional value?}}
10251025
// expected-note@-5 {{did you mean to disable error propagation?}}
@@ -1028,7 +1028,7 @@ func tryIf6() throws -> Int {
10281028
func tryIf7() throws -> Int {
10291029
let x = try if .random() { tryIf4() } else { 1 }
10301030
// expected-warning@-1 {{'try' has no effect on 'if' expression}}
1031-
// expected-error@-2 {{call can throw but is not marked with 'try'}}
1031+
// expected-warning@-2 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
10321032
// expected-note@-3 {{did you mean to use 'try'?}}
10331033
// expected-note@-4 {{did you mean to handle error as optional value?}}
10341034
// expected-note@-5 {{did you mean to disable error propagation?}}
@@ -1054,7 +1054,7 @@ func tryIf10() throws -> Int {
10541054
func tryIf11() throws -> Int {
10551055
let x = try if .random() { try tryIf4() } else { tryIf4() }
10561056
// expected-warning@-1 {{'try' has no effect on 'if' expression}}
1057-
// expected-error@-2 {{call can throw but is not marked with 'try'}}
1057+
// expected-warning@-2 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
10581058
// expected-note@-3 {{did you mean to use 'try'?}}
10591059
// expected-note@-4 {{did you mean to handle error as optional value?}}
10601060
// expected-note@-5 {{did you mean to disable error propagation?}}
@@ -1064,7 +1064,7 @@ func tryIf11() throws -> Int {
10641064
func tryIf12() throws -> Int {
10651065
let x = try if .random() { tryIf4() } else { tryIf4() }
10661066
// expected-warning@-1 {{'try' has no effect on 'if' expression}}
1067-
// expected-error@-2 2{{call can throw but is not marked with 'try'}}
1067+
// expected-warning@-2 2{{call can throw but is not marked with 'try'; this is an error in Swift 6}}
10681068
// expected-note@-3 2{{did you mean to use 'try'?}}
10691069
// expected-note@-4 2{{did you mean to handle error as optional value?}}
10701070
// expected-note@-5 2{{did you mean to disable error propagation?}}
@@ -1074,13 +1074,13 @@ func tryIf12() throws -> Int {
10741074
func tryIf13() throws -> Int {
10751075
let x = try if .random() { // expected-warning {{'try' has no effect on 'if' expression}}
10761076
tryIf4() // expected-warning {{result of call to 'tryIf4()' is unused}}
1077-
// expected-error@-1 {{call can throw but is not marked with 'try'}}
1077+
// expected-warning@-1 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
10781078
// expected-note@-2 {{did you mean to use 'try'?}}
10791079
// expected-note@-3 {{did you mean to handle error as optional value?}}
10801080
// expected-note@-4 {{did you mean to disable error propagation?}}
10811081

10821082
_ = tryIf4()
1083-
// expected-error@-1 {{call can throw but is not marked with 'try'}}
1083+
// expected-warning@-1 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
10841084
// expected-note@-2 {{did you mean to use 'try'?}}
10851085
// expected-note@-3 {{did you mean to handle error as optional value?}}
10861086
// expected-note@-4 {{did you mean to disable error propagation?}}
@@ -1105,7 +1105,7 @@ func throwsBool() throws -> Bool { true }
11051105
func tryIf14() throws -> Int {
11061106
try if throwsBool() { 0 } else { 1 }
11071107
// expected-warning@-1 {{'try' has no effect on 'if' expression}}
1108-
// expected-error@-2 {{call can throw but is not marked with 'try'}}
1108+
// expected-warning@-2 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
11091109
// expected-note@-3 {{did you mean to use 'try'?}}
11101110
// expected-note@-4 {{did you mean to handle error as optional value?}}
11111111
// expected-note@-5 {{did you mean to disable error propagation?}}
@@ -1245,21 +1245,21 @@ func awaitIf4() async -> Int {
12451245
func awaitIf5() async -> Int {
12461246
return await if .random() { awaitIf4() } else { 1 }
12471247
// expected-warning@-1 {{'await' has no effect on 'if' expression}}
1248-
// expected-error@-2 {{expression is 'async' but is not marked with 'await'}}
1248+
// expected-warning@-2 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
12491249
// expected-note@-3 {{call is 'async'}}
12501250
}
12511251

12521252
func awaitIf6() async -> Int {
12531253
await if .random() { awaitIf4() } else { 1 }
12541254
// expected-warning@-1 {{'await' has no effect on 'if' expression}}
1255-
// expected-error@-2 {{expression is 'async' but is not marked with 'await'}}
1255+
// expected-warning@-2 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
12561256
// expected-note@-3 {{call is 'async'}}
12571257
}
12581258

12591259
func awaitIf7() async -> Int {
12601260
let x = await if .random() { awaitIf4() } else { 1 }
12611261
// expected-warning@-1 {{'await' has no effect on 'if' expression}}
1262-
// expected-error@-2 {{expression is 'async' but is not marked with 'await'}}
1262+
// expected-warning@-2 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
12631263
// expected-note@-3 {{call is 'async'}}
12641264
return x
12651265
}
@@ -1283,27 +1283,27 @@ func awaitIf10() async -> Int {
12831283
func awaitIf11() async -> Int {
12841284
let x = await if .random() { await awaitIf4() } else { awaitIf4() }
12851285
// expected-warning@-1 {{'await' has no effect on 'if' expression}}
1286-
// expected-error@-2 {{expression is 'async' but is not marked with 'await'}}
1286+
// expected-warning@-2 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
12871287
// expected-note@-3 {{call is 'async'}}
12881288
return x
12891289
}
12901290

12911291
func awaitIf12() async -> Int {
12921292
let x = await if .random() { awaitIf4() } else { awaitIf4() }
12931293
// expected-warning@-1 {{'await' has no effect on 'if' expression}}
1294-
// expected-error@-2 2{{expression is 'async' but is not marked with 'await'}}
1294+
// expected-warning@-2 2{{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
12951295
// expected-note@-3 2{{call is 'async'}}
12961296
return x
12971297
}
12981298

12991299
func awaitIf13() async throws -> Int {
13001300
let x = await if .random() { // expected-warning {{'await' has no effect on 'if' expression}}
13011301
awaitIf4() // expected-warning {{result of call to 'awaitIf4()' is unused}}
1302-
// expected-error@-1 {{expression is 'async' but is not marked with 'await'}}
1302+
// expected-warning@-1 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
13031303
// expected-note@-2 {{call is 'async'}}
13041304

13051305
_ = awaitIf4()
1306-
// expected-error@-1 {{expression is 'async' but is not marked with 'await'}}
1306+
// expected-warning@-1 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
13071307
// expected-note@-2 {{call is 'async'}}
13081308

13091309
_ = await awaitIf4() // Okay.
@@ -1326,7 +1326,7 @@ func asyncBool() async -> Bool { true }
13261326
func awaitIf14() async -> Int {
13271327
await if asyncBool() { 0 } else { 1 }
13281328
// expected-warning@-1 {{'await' has no effect on 'if' expression}}
1329-
// expected-error@-2 {{expression is 'async' but is not marked with 'await'}}
1329+
// expected-warning@-2 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
13301330
// expected-note@-3 {{call is 'async'}}
13311331
}
13321332

@@ -1378,27 +1378,27 @@ func tryAwaitIf3() async throws -> Int {
13781378
try await if .random() { tryAwaitIf2() } else { 1 } as Int
13791379
// expected-warning@-1 {{'try' has no effect on 'if' expression}}
13801380
// expected-warning@-2 {{'await' has no effect on 'if' expression}}
1381-
// expected-error@-3 {{call can throw but is not marked with 'try'}}
1381+
// expected-warning@-3 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
13821382
// expected-note@-4 {{did you mean to use 'try'?}}
13831383
// expected-note@-5 {{did you mean to handle error as optional value?}}
13841384
// expected-note@-6 {{did you mean to disable error propagation?}}
1385-
// expected-error@-7 {{expression is 'async' but is not marked with 'await'}}
1385+
// expected-warning@-7 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
13861386
// expected-note@-8 {{call is 'async'}}
13871387
}
13881388

13891389
func tryAwaitIf4() async throws -> Int {
13901390
try await if .random() { try tryAwaitIf2() } else { 1 } as Int
13911391
// expected-warning@-1 {{'try' has no effect on 'if' expression}}
13921392
// expected-warning@-2 {{'await' has no effect on 'if' expression}}
1393-
// expected-error@-3 {{expression is 'async' but is not marked with 'await'}}
1393+
// expected-warning@-3 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
13941394
// expected-note@-4 {{call is 'async'}}
13951395
}
13961396

13971397
func tryAwaitIf5() async throws -> Int {
13981398
try await if .random() { await tryAwaitIf2() } else { 1 } as Int
13991399
// expected-warning@-1 {{'try' has no effect on 'if' expression}}
14001400
// expected-warning@-2 {{'await' has no effect on 'if' expression}}
1401-
// expected-error@-3 {{call can throw but is not marked with 'try'}}
1401+
// expected-warning@-3 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
14021402
// expected-note@-4 {{did you mean to use 'try'?}}
14031403
// expected-note@-5 {{did you mean to handle error as optional value?}}
14041404
// expected-note@-6 {{did you mean to disable error propagation?}}
@@ -1414,27 +1414,27 @@ func tryAwaitIf7() async throws -> Int {
14141414
try await if .random() { tryAwaitIf2() } else { 1 }
14151415
// expected-warning@-1 {{'try' has no effect on 'if' expression}}
14161416
// expected-warning@-2 {{'await' has no effect on 'if' expression}}
1417-
// expected-error@-3 {{call can throw but is not marked with 'try'}}
1417+
// expected-warning@-3 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
14181418
// expected-note@-4 {{did you mean to use 'try'?}}
14191419
// expected-note@-5 {{did you mean to handle error as optional value?}}
14201420
// expected-note@-6 {{did you mean to disable error propagation?}}
1421-
// expected-error@-7 {{expression is 'async' but is not marked with 'await'}}
1421+
// expected-warning@-7 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
14221422
// expected-note@-8 {{call is 'async'}}
14231423
}
14241424

14251425
func tryAwaitIf8() async throws -> Int {
14261426
try await if .random() { try tryAwaitIf2() } else { 1 }
14271427
// expected-warning@-1 {{'try' has no effect on 'if' expression}}
14281428
// expected-warning@-2 {{'await' has no effect on 'if' expression}}
1429-
// expected-error@-3 {{expression is 'async' but is not marked with 'await'}}
1429+
// expected-warning@-3 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
14301430
// expected-note@-4 {{call is 'async'}}
14311431
}
14321432

14331433
func tryAwaitIf9() async throws -> Int {
14341434
try await if .random() { await tryAwaitIf2() } else { 1 }
14351435
// expected-warning@-1 {{'try' has no effect on 'if' expression}}
14361436
// expected-warning@-2 {{'await' has no effect on 'if' expression}}
1437-
// expected-error@-3 {{call can throw but is not marked with 'try'}}
1437+
// expected-warning@-3 {{call can throw but is not marked with 'try'; this is an error in Swift 6}}
14381438
// expected-note@-4 {{did you mean to use 'try'?}}
14391439
// expected-note@-5 {{did you mean to handle error as optional value?}}
14401440
// expected-note@-6 {{did you mean to disable error propagation?}}

0 commit comments

Comments
 (0)