@@ -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:
@@ -2562,6 +2564,15 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
25622564
25632565 // / Do we have any 'await's in this context?
25642566 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 ,
25652576 };
25662577 private:
25672578 unsigned Bits;
@@ -2707,8 +2718,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
27072718 }
27082719
27092720 void enterAsyncLet () {
2710- Self.Flags .set (ContextFlags::IsTryCovered);
2711- Self.Flags .set (ContextFlags::IsAsyncCovered);
2721+ Self.Flags .set (ContextFlags::InAsyncLet);
27122722 }
27132723
27142724 void refineLocalContext (Context newContext) {
@@ -2730,6 +2740,9 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
27302740 Self.Flags .reset ();
27312741 Self.MaxThrowingKind = ConditionalEffectKind::None;
27322742
2743+ Self.Flags .mergeFrom (ContextFlags::StmtExprCoversTry, OldFlags);
2744+ Self.Flags .mergeFrom (ContextFlags::StmtExprCoversAwait, OldFlags);
2745+
27332746 // Suppress 'try' coverage checking within a single level of
27342747 // do/catch in debugger functions.
27352748 if (OldFlags.has (ContextFlags::IsTopLevelDebuggerFunction))
@@ -2747,6 +2760,17 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
27472760 // 'async'.
27482761 }
27492762
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+
27502774 void preserveCoverageFromSingleValueStmtExpr () {
27512775 // We need to preserve whether we saw any throwing sites, to avoid warning
27522776 // on 'do { let x = if .random() { try ... } else { ... } } catch { ... }'
@@ -2918,7 +2942,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
29182942 // For an if/switch expression, we reset coverage such that a 'try'/'await'
29192943 // does not cover the branches.
29202944 ContextScope scope (*this , /* newContext*/ llvm::None);
2921- scope.resetCoverage ();
2945+ scope.setCoverageForSingleValueStmtExpr ();
29222946 SVE->getStmt ()->walk (*this );
29232947 scope.preserveCoverageFromSingleValueStmtExpr ();
29242948 return ShouldNotRecurse;
@@ -3145,7 +3169,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
31453169
31463170 ThrownErrorDestination
31473171 checkThrowAsyncSite (ASTNode E, bool requiresTry,
3148- const Classification &classification) {
3172+ Classification &classification) {
31493173 // Suppress all diagnostics when there's an un-analyzable throw/async site.
31503174 if (classification.isInvalid ()) {
31513175 Flags.set (ContextFlags::HasAnyThrowSite);
@@ -3173,10 +3197,13 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
31733197 classification.getAsyncReason ());
31743198 }
31753199 // 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))) {
31773202 Expr *expr = E.dyn_cast <Expr*>();
31783203 Expr *anchor = walkToAnchor (expr, parentMap,
31793204 CurContext.isWithinInterpolatedString ());
3205+ if (Flags.has (ContextFlags::StmtExprCoversAwait))
3206+ classification.setDowngradeToWarning (true );
31803207 if (uncoveredAsync.find (anchor) == uncoveredAsync.end ())
31813208 errorOrder.push_back (anchor);
31823209 uncoveredAsync[anchor].emplace_back (
@@ -3209,13 +3236,16 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
32093236 break ;
32103237
32113238 bool isTryCovered =
3212- (!requiresTry || Flags.has (ContextFlags::IsTryCovered));
3239+ (!requiresTry || Flags.has (ContextFlags::IsTryCovered) ||
3240+ Flags.has (ContextFlags::InAsyncLet));
32133241 if (!CurContext.handlesThrows (throwsKind)) {
32143242 CurContext.diagnoseUnhandledThrowSite (Ctx.Diags , E, isTryCovered,
32153243 classification.getThrowReason ());
32163244 } else if (!isTryCovered) {
3245+ if (Flags.has (ContextFlags::StmtExprCoversTry))
3246+ classification.setDowngradeToWarning (true );
32173247 CurContext.diagnoseUncoveredThrowSite (Ctx, E, // we want this one to trigger
3218- classification. getThrowReason () );
3248+ classification);
32193249 } else {
32203250 return checkThrownErrorType (
32213251 E.getStartLoc (), classification.getThrownError ());
@@ -3367,7 +3397,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
33673397
33683398 void diagnoseRedundantTry (AnyTryExpr *E) const {
33693399 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.
33713401 Ctx.Diags .diagnose (E->getTryLoc (),
33723402 diag::effect_marker_on_single_value_stmt,
33733403 " try" , SVE->getStmt ()->getKind ())
@@ -3379,7 +3409,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
33793409
33803410 void diagnoseRedundantAwait (AwaitExpr *E) const {
33813411 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.
33833413 Ctx.Diags .diagnose (E->getAwaitLoc (),
33843414 diag::effect_marker_on_single_value_stmt,
33853415 " await" , SVE->getStmt ()->getKind ())
0 commit comments