@@ -2220,9 +2220,10 @@ class Context {
2220
2220
}
2221
2221
2222
2222
void diagnoseUncoveredThrowSite (ASTContext &ctx, ASTNode E,
2223
- const PotentialEffectReason &reason ) {
2223
+ const Classification &classification ) {
2224
2224
auto &Diags = ctx.Diags ;
2225
2225
auto message = diag::throwing_call_without_try;
2226
+ const auto &reason = classification.getThrowReason ();
2226
2227
auto reasonKind = reason.getKind ();
2227
2228
2228
2229
bool suggestTryFixIt = reasonKind == PotentialEffectReason::Kind::Apply;
@@ -2262,7 +2263,8 @@ class Context {
2262
2263
}
2263
2264
}
2264
2265
2265
- Diags.diagnose (loc, message).highlight (highlight);
2266
+ Diags.diagnose (loc, message).highlight (highlight)
2267
+ .warnUntilSwiftVersionIf (classification.shouldDowngradeToWarning (), 6 );
2266
2268
maybeAddRethrowsNote (Diags, loc, reason);
2267
2269
2268
2270
// If this is a call without expected 'try[?|!]', like this:
@@ -2562,6 +2564,15 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2562
2564
2563
2565
// / Do we have any 'await's in this context?
2564
2566
HasAnyAwait = 0x80 ,
2567
+
2568
+ // / Are we in an 'async let' initializer context?
2569
+ 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 ,
2565
2576
};
2566
2577
private:
2567
2578
unsigned Bits;
@@ -2707,8 +2718,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2707
2718
}
2708
2719
2709
2720
void enterAsyncLet () {
2710
- Self.Flags .set (ContextFlags::IsTryCovered);
2711
- Self.Flags .set (ContextFlags::IsAsyncCovered);
2721
+ Self.Flags .set (ContextFlags::InAsyncLet);
2712
2722
}
2713
2723
2714
2724
void refineLocalContext (Context newContext) {
@@ -2730,6 +2740,9 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2730
2740
Self.Flags .reset ();
2731
2741
Self.MaxThrowingKind = ConditionalEffectKind::None;
2732
2742
2743
+ Self.Flags .mergeFrom (ContextFlags::StmtExprCoversTry, OldFlags);
2744
+ Self.Flags .mergeFrom (ContextFlags::StmtExprCoversAwait, OldFlags);
2745
+
2733
2746
// Suppress 'try' coverage checking within a single level of
2734
2747
// do/catch in debugger functions.
2735
2748
if (OldFlags.has (ContextFlags::IsTopLevelDebuggerFunction))
@@ -2747,6 +2760,17 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2747
2760
// 'async'.
2748
2761
}
2749
2762
2763
+ void setCoverageForSingleValueStmtExpr () {
2764
+ resetCoverage ();
2765
+ 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);
2772
+ }
2773
+
2750
2774
void preserveCoverageFromSingleValueStmtExpr () {
2751
2775
// We need to preserve whether we saw any throwing sites, to avoid warning
2752
2776
// on 'do { let x = if .random() { try ... } else { ... } } catch { ... }'
@@ -2918,7 +2942,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2918
2942
// For an if/switch expression, we reset coverage such that a 'try'/'await'
2919
2943
// does not cover the branches.
2920
2944
ContextScope scope (*this , /* newContext*/ llvm::None);
2921
- scope.resetCoverage ();
2945
+ scope.setCoverageForSingleValueStmtExpr ();
2922
2946
SVE->getStmt ()->walk (*this );
2923
2947
scope.preserveCoverageFromSingleValueStmtExpr ();
2924
2948
return ShouldNotRecurse;
@@ -3145,7 +3169,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
3145
3169
3146
3170
ThrownErrorDestination
3147
3171
checkThrowAsyncSite (ASTNode E, bool requiresTry,
3148
- const Classification &classification) {
3172
+ Classification &classification) {
3149
3173
// Suppress all diagnostics when there's an un-analyzable throw/async site.
3150
3174
if (classification.isInvalid ()) {
3151
3175
Flags.set (ContextFlags::HasAnyThrowSite);
@@ -3173,10 +3197,13 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
3173
3197
classification.getAsyncReason ());
3174
3198
}
3175
3199
// Diagnose async calls that are outside of an await context.
3176
- else if (!Flags.has (ContextFlags::IsAsyncCovered)) {
3200
+ else if (!(Flags.has (ContextFlags::IsAsyncCovered) ||
3201
+ Flags.has (ContextFlags::InAsyncLet))) {
3177
3202
Expr *expr = E.dyn_cast <Expr*>();
3178
3203
Expr *anchor = walkToAnchor (expr, parentMap,
3179
3204
CurContext.isWithinInterpolatedString ());
3205
+ if (Flags.has (ContextFlags::StmtExprCoversAwait))
3206
+ classification.setDowngradeToWarning (true );
3180
3207
if (uncoveredAsync.find (anchor) == uncoveredAsync.end ())
3181
3208
errorOrder.push_back (anchor);
3182
3209
uncoveredAsync[anchor].emplace_back (
@@ -3209,13 +3236,16 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
3209
3236
break ;
3210
3237
3211
3238
bool isTryCovered =
3212
- (!requiresTry || Flags.has (ContextFlags::IsTryCovered));
3239
+ (!requiresTry || Flags.has (ContextFlags::IsTryCovered) ||
3240
+ Flags.has (ContextFlags::InAsyncLet));
3213
3241
if (!CurContext.handlesThrows (throwsKind)) {
3214
3242
CurContext.diagnoseUnhandledThrowSite (Ctx.Diags , E, isTryCovered,
3215
3243
classification.getThrowReason ());
3216
3244
} else if (!isTryCovered) {
3245
+ if (Flags.has (ContextFlags::StmtExprCoversTry))
3246
+ classification.setDowngradeToWarning (true );
3217
3247
CurContext.diagnoseUncoveredThrowSite (Ctx, E, // we want this one to trigger
3218
- classification. getThrowReason () );
3248
+ classification);
3219
3249
} else {
3220
3250
return checkThrownErrorType (
3221
3251
E.getStartLoc (), classification.getThrownError ());
@@ -3367,7 +3397,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
3367
3397
3368
3398
void diagnoseRedundantTry (AnyTryExpr *E) const {
3369
3399
if (auto *SVE = SingleValueStmtExpr::tryDigOutSingleValueStmtExpr (E)) {
3370
- // For an if/switch expression, produce an error instead of a warning.
3400
+ // For an if/switch expression, produce a tailored warning.
3371
3401
Ctx.Diags .diagnose (E->getTryLoc (),
3372
3402
diag::effect_marker_on_single_value_stmt,
3373
3403
" try" , SVE->getStmt ()->getKind ())
@@ -3379,7 +3409,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
3379
3409
3380
3410
void diagnoseRedundantAwait (AwaitExpr *E) const {
3381
3411
if (auto *SVE = SingleValueStmtExpr::tryDigOutSingleValueStmtExpr (E)) {
3382
- // For an if/switch expression, produce an error instead of a warning.
3412
+ // For an if/switch expression, produce a tailored warning.
3383
3413
Ctx.Diags .diagnose (E->getAwaitLoc (),
3384
3414
diag::effect_marker_on_single_value_stmt,
3385
3415
" await" , SVE->getStmt ()->getKind ())
0 commit comments