@@ -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:
@@ -2051,6 +2053,15 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
20512053
20522054 // / Do we have any 'await's in this context?
20532055 HasAnyAwait = 0x80 ,
2056+
2057+ // / Are we in an 'async let' initializer context?
2058+ 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 ,
20542065 };
20552066 private:
20562067 unsigned Bits;
@@ -2196,8 +2207,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
21962207 }
21972208
21982209 void enterAsyncLet () {
2199- Self.Flags .set (ContextFlags::IsTryCovered);
2200- Self.Flags .set (ContextFlags::IsAsyncCovered);
2210+ Self.Flags .set (ContextFlags::InAsyncLet);
22012211 }
22022212
22032213 void refineLocalContext (Context newContext) {
@@ -2219,6 +2229,9 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
22192229 Self.Flags .reset ();
22202230 Self.MaxThrowingKind = ConditionalEffectKind::None;
22212231
2232+ Self.Flags .mergeFrom (ContextFlags::StmtExprCoversTry, OldFlags);
2233+ Self.Flags .mergeFrom (ContextFlags::StmtExprCoversAwait, OldFlags);
2234+
22222235 // Suppress 'try' coverage checking within a single level of
22232236 // do/catch in debugger functions.
22242237 if (OldFlags.has (ContextFlags::IsTopLevelDebuggerFunction))
@@ -2236,6 +2249,17 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
22362249 // 'async'.
22372250 }
22382251
2252+ void setCoverageForSingleValueStmtExpr () {
2253+ resetCoverage ();
2254+ 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);
2261+ }
2262+
22392263 void preserveCoverageFromSingleValueStmtExpr () {
22402264 // We need to preserve whether we saw any throwing sites, to avoid warning
22412265 // on 'do { let x = if .random() { try ... } else { ... } } catch { ... }'
@@ -2393,7 +2417,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
23932417 // For an if/switch expression, we reset coverage such that a 'try'/'await'
23942418 // does not cover the branches.
23952419 ContextScope scope (*this , /* newContext*/ llvm::None);
2396- scope.resetCoverage ();
2420+ scope.setCoverageForSingleValueStmtExpr ();
23972421 SVE->getStmt ()->walk (*this );
23982422 scope.preserveCoverageFromSingleValueStmtExpr ();
23992423 return ShouldNotRecurse;
@@ -2549,11 +2573,11 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
25492573 effects.push_back (EffectKind::Async);
25502574 }
25512575
2576+ auto classification = Classification::forEffect (effects,
2577+ ConditionalEffectKind::Always,
2578+ getKindOfEffectfulProp (member));
25522579 bool requiresTry = getter->hasThrows ();
2553- checkThrowAsyncSite (E, requiresTry,
2554- Classification::forEffect (effects,
2555- ConditionalEffectKind::Always,
2556- getKindOfEffectfulProp (member)));
2580+ checkThrowAsyncSite (E, requiresTry, classification);
25572581
25582582 } else {
25592583 EffectList effects;
@@ -2593,10 +2617,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
25932617 effects.push_back (EffectKind::Async);
25942618 }
25952619
2596- checkThrowAsyncSite (E, getter-> hasThrows () ,
2597- Classification::forEffect (effects ,
2598- ConditionalEffectKind::Always,
2599- PotentialEffectReason::forPropertyAccess ()) );
2620+ auto classification = Classification::forEffect (effects ,
2621+ ConditionalEffectKind::Always ,
2622+ PotentialEffectReason::forPropertyAccess ());
2623+ checkThrowAsyncSite (E, getter-> hasThrows (), classification );
26002624
26012625 } else if (E->isImplicitlyAsync ()) {
26022626 auto classification = Classification::forUnconditional (
@@ -2706,7 +2730,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
27062730 }
27072731
27082732 void checkThrowAsyncSite (ASTNode E, bool requiresTry,
2709- const Classification &classification) {
2733+ Classification &classification) {
27102734 // Suppress all diagnostics when there's an un-analyzable throw/async site.
27112735 if (classification.isInvalid ()) {
27122736 Flags.set (ContextFlags::HasAnyThrowSite);
@@ -2734,10 +2758,13 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
27342758 classification.getAsyncReason ());
27352759 }
27362760 // Diagnose async calls that are outside of an await context.
2737- else if (!Flags.has (ContextFlags::IsAsyncCovered)) {
2761+ else if (!(Flags.has (ContextFlags::IsAsyncCovered) ||
2762+ Flags.has (ContextFlags::InAsyncLet))) {
27382763 Expr *expr = E.dyn_cast <Expr*>();
27392764 Expr *anchor = walkToAnchor (expr, parentMap,
27402765 CurContext.isWithinInterpolatedString ());
2766+ if (Flags.has (ContextFlags::StmtExprCoversAwait))
2767+ classification.setDowngradeToWarning (true );
27412768 if (uncoveredAsync.find (anchor) == uncoveredAsync.end ())
27422769 errorOrder.push_back (anchor);
27432770 uncoveredAsync[anchor].emplace_back (
@@ -2770,13 +2797,16 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
27702797 break ;
27712798
27722799 bool isTryCovered =
2773- (!requiresTry || Flags.has (ContextFlags::IsTryCovered));
2800+ (!requiresTry || Flags.has (ContextFlags::IsTryCovered) ||
2801+ Flags.has (ContextFlags::InAsyncLet));
27742802 if (!CurContext.handlesThrows (throwsKind)) {
27752803 CurContext.diagnoseUnhandledThrowSite (Ctx.Diags , E, isTryCovered,
27762804 classification.getThrowReason ());
27772805 } else if (!isTryCovered) {
2806+ if (Flags.has (ContextFlags::StmtExprCoversTry))
2807+ classification.setDowngradeToWarning (true );
27782808 CurContext.diagnoseUncoveredThrowSite (Ctx, E, // we want this one to trigger
2779- classification. getThrowReason () );
2809+ classification);
27802810 }
27812811 break ;
27822812 }
@@ -2893,7 +2923,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
28932923
28942924 void diagnoseRedundantTry (AnyTryExpr *E) const {
28952925 if (auto *SVE = SingleValueStmtExpr::tryDigOutSingleValueStmtExpr (E)) {
2896- // For an if/switch expression, produce an error instead of a warning.
2926+ // For an if/switch expression, produce a tailored warning.
28972927 Ctx.Diags .diagnose (E->getTryLoc (),
28982928 diag::effect_marker_on_single_value_stmt,
28992929 " try" , SVE->getStmt ()->getKind ())
@@ -2905,7 +2935,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
29052935
29062936 void diagnoseRedundantAwait (AwaitExpr *E) const {
29072937 if (auto *SVE = SingleValueStmtExpr::tryDigOutSingleValueStmtExpr (E)) {
2908- // For an if/switch expression, produce an error instead of a warning.
2938+ // For an if/switch expression, produce a tailored warning.
29092939 Ctx.Diags .diagnose (E->getAwaitLoc (),
29102940 diag::effect_marker_on_single_value_stmt,
29112941 " await" , SVE->getStmt ()->getKind ())
0 commit comments