@@ -1709,9 +1709,10 @@ class Context {
1709
1709
}
1710
1710
1711
1711
void diagnoseUncoveredThrowSite (ASTContext &ctx, ASTNode E,
1712
- const PotentialEffectReason &reason ) {
1712
+ const Classification &classification ) {
1713
1713
auto &Diags = ctx.Diags ;
1714
1714
auto message = diag::throwing_call_without_try;
1715
+ const auto &reason = classification.getThrowReason ();
1715
1716
auto reasonKind = reason.getKind ();
1716
1717
1717
1718
bool suggestTryFixIt = reasonKind == PotentialEffectReason::Kind::Apply;
@@ -1751,7 +1752,8 @@ class Context {
1751
1752
}
1752
1753
}
1753
1754
1754
- Diags.diagnose (loc, message).highlight (highlight);
1755
+ Diags.diagnose (loc, message).highlight (highlight)
1756
+ .warnUntilSwiftVersionIf (classification.shouldDowngradeToWarning (), 6 );
1755
1757
maybeAddRethrowsNote (Diags, loc, reason);
1756
1758
1757
1759
// If this is a call without expected 'try[?|!]', like this:
@@ -2051,6 +2053,15 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2051
2053
2052
2054
// / Do we have any 'await's in this context?
2053
2055
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 ,
2054
2065
};
2055
2066
private:
2056
2067
unsigned Bits;
@@ -2196,8 +2207,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2196
2207
}
2197
2208
2198
2209
void enterAsyncLet () {
2199
- Self.Flags .set (ContextFlags::IsTryCovered);
2200
- Self.Flags .set (ContextFlags::IsAsyncCovered);
2210
+ Self.Flags .set (ContextFlags::InAsyncLet);
2201
2211
}
2202
2212
2203
2213
void refineLocalContext (Context newContext) {
@@ -2219,6 +2229,9 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2219
2229
Self.Flags .reset ();
2220
2230
Self.MaxThrowingKind = ConditionalEffectKind::None;
2221
2231
2232
+ Self.Flags .mergeFrom (ContextFlags::StmtExprCoversTry, OldFlags);
2233
+ Self.Flags .mergeFrom (ContextFlags::StmtExprCoversAwait, OldFlags);
2234
+
2222
2235
// Suppress 'try' coverage checking within a single level of
2223
2236
// do/catch in debugger functions.
2224
2237
if (OldFlags.has (ContextFlags::IsTopLevelDebuggerFunction))
@@ -2236,6 +2249,17 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2236
2249
// 'async'.
2237
2250
}
2238
2251
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
+
2239
2263
void preserveCoverageFromSingleValueStmtExpr () {
2240
2264
// We need to preserve whether we saw any throwing sites, to avoid warning
2241
2265
// on 'do { let x = if .random() { try ... } else { ... } } catch { ... }'
@@ -2393,7 +2417,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2393
2417
// For an if/switch expression, we reset coverage such that a 'try'/'await'
2394
2418
// does not cover the branches.
2395
2419
ContextScope scope (*this , /* newContext*/ llvm::None);
2396
- scope.resetCoverage ();
2420
+ scope.setCoverageForSingleValueStmtExpr ();
2397
2421
SVE->getStmt ()->walk (*this );
2398
2422
scope.preserveCoverageFromSingleValueStmtExpr ();
2399
2423
return ShouldNotRecurse;
@@ -2549,11 +2573,11 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2549
2573
effects.push_back (EffectKind::Async);
2550
2574
}
2551
2575
2576
+ auto classification = Classification::forEffect (effects,
2577
+ ConditionalEffectKind::Always,
2578
+ getKindOfEffectfulProp (member));
2552
2579
bool requiresTry = getter->hasThrows ();
2553
- checkThrowAsyncSite (E, requiresTry,
2554
- Classification::forEffect (effects,
2555
- ConditionalEffectKind::Always,
2556
- getKindOfEffectfulProp (member)));
2580
+ checkThrowAsyncSite (E, requiresTry, classification);
2557
2581
2558
2582
} else {
2559
2583
EffectList effects;
@@ -2593,10 +2617,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2593
2617
effects.push_back (EffectKind::Async);
2594
2618
}
2595
2619
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 );
2600
2624
2601
2625
} else if (E->isImplicitlyAsync ()) {
2602
2626
auto classification = Classification::forUnconditional (
@@ -2706,7 +2730,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2706
2730
}
2707
2731
2708
2732
void checkThrowAsyncSite (ASTNode E, bool requiresTry,
2709
- const Classification &classification) {
2733
+ Classification &classification) {
2710
2734
// Suppress all diagnostics when there's an un-analyzable throw/async site.
2711
2735
if (classification.isInvalid ()) {
2712
2736
Flags.set (ContextFlags::HasAnyThrowSite);
@@ -2734,10 +2758,13 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2734
2758
classification.getAsyncReason ());
2735
2759
}
2736
2760
// 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))) {
2738
2763
Expr *expr = E.dyn_cast <Expr*>();
2739
2764
Expr *anchor = walkToAnchor (expr, parentMap,
2740
2765
CurContext.isWithinInterpolatedString ());
2766
+ if (Flags.has (ContextFlags::StmtExprCoversAwait))
2767
+ classification.setDowngradeToWarning (true );
2741
2768
if (uncoveredAsync.find (anchor) == uncoveredAsync.end ())
2742
2769
errorOrder.push_back (anchor);
2743
2770
uncoveredAsync[anchor].emplace_back (
@@ -2770,13 +2797,16 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2770
2797
break ;
2771
2798
2772
2799
bool isTryCovered =
2773
- (!requiresTry || Flags.has (ContextFlags::IsTryCovered));
2800
+ (!requiresTry || Flags.has (ContextFlags::IsTryCovered) ||
2801
+ Flags.has (ContextFlags::InAsyncLet));
2774
2802
if (!CurContext.handlesThrows (throwsKind)) {
2775
2803
CurContext.diagnoseUnhandledThrowSite (Ctx.Diags , E, isTryCovered,
2776
2804
classification.getThrowReason ());
2777
2805
} else if (!isTryCovered) {
2806
+ if (Flags.has (ContextFlags::StmtExprCoversTry))
2807
+ classification.setDowngradeToWarning (true );
2778
2808
CurContext.diagnoseUncoveredThrowSite (Ctx, E, // we want this one to trigger
2779
- classification. getThrowReason () );
2809
+ classification);
2780
2810
}
2781
2811
break ;
2782
2812
}
@@ -2893,7 +2923,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2893
2923
2894
2924
void diagnoseRedundantTry (AnyTryExpr *E) const {
2895
2925
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.
2897
2927
Ctx.Diags .diagnose (E->getTryLoc (),
2898
2928
diag::effect_marker_on_single_value_stmt,
2899
2929
" try" , SVE->getStmt ()->getKind ())
@@ -2905,7 +2935,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2905
2935
2906
2936
void diagnoseRedundantAwait (AwaitExpr *E) const {
2907
2937
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.
2909
2939
Ctx.Diags .diagnose (E->getAwaitLoc (),
2910
2940
diag::effect_marker_on_single_value_stmt,
2911
2941
" await" , SVE->getStmt ()->getKind ())
0 commit comments