@@ -1907,67 +1907,6 @@ class Context {
1907
1907
}
1908
1908
}
1909
1909
1910
- void diagnoseUncoveredAsyncSite (ASTContext &ctx, ASTNode node,
1911
- PotentialEffectReason reason) {
1912
- SourceRange highlight = node.getSourceRange ();
1913
- auto diag = diag::async_call_without_await;
1914
-
1915
- switch (reason.getKind ()) {
1916
- case PotentialEffectReason::Kind::AsyncLet:
1917
- // Reference to an 'async let' missing an 'await'.
1918
- if (auto declR = dyn_cast_or_null<DeclRefExpr>(node.dyn_cast <Expr*>())) {
1919
- if (auto var = dyn_cast<VarDecl>(declR->getDecl ())) {
1920
- if (var->isAsyncLet ()) {
1921
- ctx.Diags .diagnose (declR->getLoc (), diag::async_let_without_await,
1922
- var->getName ());
1923
- return ;
1924
- }
1925
- }
1926
- }
1927
- LLVM_FALLTHROUGH; // fallthrough to a message about property access
1928
-
1929
- case PotentialEffectReason::Kind::PropertyAccess:
1930
- diag = diag::async_prop_access_without_await;
1931
- break ;
1932
-
1933
- case PotentialEffectReason::Kind::SubscriptAccess:
1934
- diag = diag::async_subscript_access_without_await;
1935
- break ;
1936
-
1937
- case PotentialEffectReason::Kind::ByClosure:
1938
- case PotentialEffectReason::Kind::ByDefaultClosure:
1939
- case PotentialEffectReason::Kind::ByConformance:
1940
- case PotentialEffectReason::Kind::Apply: {
1941
- if (Function) {
1942
- // To produce a better error message, check if it is an autoclosure.
1943
- // We do not use 'Context::isAutoClosure' b/c it gives conservative
1944
- // answers.
1945
- if (auto autoclosure = dyn_cast_or_null<AutoClosureExpr>(
1946
- Function->getAbstractClosureExpr ())) {
1947
- switch (autoclosure->getThunkKind ()) {
1948
- case AutoClosureExpr::Kind::None:
1949
- diag = diag::async_call_without_await_in_autoclosure;
1950
- break ;
1951
-
1952
- case AutoClosureExpr::Kind::AsyncLet:
1953
- diag = diag::async_call_without_await_in_async_let;
1954
- break ;
1955
-
1956
- case AutoClosureExpr::Kind::SingleCurryThunk:
1957
- case AutoClosureExpr::Kind::DoubleCurryThunk:
1958
- break ;
1959
- }
1960
- }
1961
- }
1962
- break ;
1963
- }
1964
- };
1965
-
1966
- ctx.Diags .diagnose (node.getStartLoc (), diag)
1967
- .fixItInsert (node.getStartLoc (), " await " )
1968
- .highlight (highlight);
1969
- }
1970
-
1971
1910
void diagnoseAsyncInIllegalContext (DiagnosticEngine &Diags, ASTNode node) {
1972
1911
if (auto *e = node.dyn_cast <Expr*>()) {
1973
1912
if (isa<ApplyExpr>(e)) {
@@ -2119,8 +2058,43 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2119
2058
// / context.
2120
2059
ConditionalEffectKind MaxThrowingKind;
2121
2060
2061
+ struct DiagnosticInfo {
2062
+ DiagnosticInfo (Expr &failingExpr,
2063
+ PotentialEffectReason reason) :
2064
+ reason (reason),
2065
+ expr (failingExpr) {}
2066
+
2067
+ // / Reason for throwing
2068
+ PotentialEffectReason reason;
2069
+
2070
+ // / Failing expression
2071
+ Expr &expr;
2072
+ };
2073
+
2074
+ SmallVector<Expr *, 4 > errorOrder;
2075
+ llvm::DenseMap<Expr *, std::vector<DiagnosticInfo>> uncoveredAsync;
2122
2076
llvm::DenseMap<Expr *, Expr *> parentMap;
2123
2077
2078
+ static bool isEffectAnchor (Expr *e) {
2079
+ return isa<AbstractClosureExpr>(e) || isa<DiscardAssignmentExpr>(e) || isa<AssignExpr>(e);
2080
+ }
2081
+
2082
+ static bool isAnchorTooEarly (Expr *e) {
2083
+ return isa<AssignExpr>(e) || isa<DiscardAssignmentExpr>(e);
2084
+ }
2085
+
2086
+ // / Find the top location where we should put the await
2087
+ static Expr* walkToAnchor (Expr *e,
2088
+ llvm::DenseMap<Expr *, Expr*> &parentMap) {
2089
+ Expr *parent = e;
2090
+ Expr *lastParent = e;
2091
+ while (parent && !isEffectAnchor (parent)) {
2092
+ lastParent = parent;
2093
+ parent = parentMap[parent];
2094
+ }
2095
+ return parent && !isAnchorTooEarly (parent) ? parent : lastParent;
2096
+ }
2097
+
2124
2098
void flagInvalidCode () {
2125
2099
// Suppress warnings about useless try or catch.
2126
2100
Flags.set (ContextFlags::HasAnyThrowSite);
@@ -2282,6 +2256,13 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2282
2256
}
2283
2257
}
2284
2258
2259
+ ~CheckEffectsCoverage () {
2260
+ for (Expr *anchor: errorOrder) {
2261
+ diagnoseUncoveredAsyncSite (anchor);
2262
+ }
2263
+ }
2264
+
2265
+
2285
2266
// / Mark that the current context is top-level code with
2286
2267
// / throw-without-try enabled.
2287
2268
void setTopLevelThrowWithoutTry () {
@@ -2638,8 +2619,17 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2638
2619
}
2639
2620
// Diagnose async calls that are outside of an await context.
2640
2621
else if (!Flags.has (ContextFlags::IsAsyncCovered)) {
2641
- CurContext.diagnoseUncoveredAsyncSite (Ctx, E,
2642
- classification.getAsyncReason ());
2622
+ Expr *expr = E.dyn_cast <Expr*>();
2623
+ Expr *anchor = walkToAnchor (expr, parentMap);
2624
+
2625
+ auto key = uncoveredAsync.find (anchor);
2626
+ if (key == uncoveredAsync.end ()) {
2627
+ uncoveredAsync.insert ({anchor, {}});
2628
+ errorOrder.push_back (anchor);
2629
+ }
2630
+ uncoveredAsync[anchor].emplace_back (
2631
+ *expr,
2632
+ classification.getAsyncReason ());
2643
2633
}
2644
2634
}
2645
2635
@@ -2788,6 +2778,78 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2788
2778
2789
2779
return ShouldRecurse;
2790
2780
}
2781
+
2782
+ void diagnoseUncoveredAsyncSite (const Expr *anchor) const {
2783
+ auto asyncPointIter = uncoveredAsync.find (anchor);
2784
+ if (asyncPointIter == uncoveredAsync.end ())
2785
+ return ;
2786
+ const std::vector<DiagnosticInfo> &errors = asyncPointIter->getSecond ();
2787
+ SourceLoc awaitInsertLoc = anchor->getStartLoc ();
2788
+ if (const AnyTryExpr *tryExpr = dyn_cast<AnyTryExpr>(anchor))
2789
+ awaitInsertLoc = tryExpr->getSubExpr ()->getStartLoc ();
2790
+ else if (const AutoClosureExpr *autoClosure = dyn_cast<AutoClosureExpr>(anchor)) {
2791
+ if (const AnyTryExpr *tryExpr = dyn_cast<AnyTryExpr>(autoClosure->getSingleExpressionBody ()))
2792
+ awaitInsertLoc = tryExpr->getSubExpr ()->getStartLoc ();
2793
+ }
2794
+
2795
+ Ctx.Diags .diagnose (anchor->getStartLoc (), diag::async_expr_without_await)
2796
+ .fixItInsert (awaitInsertLoc, " await " )
2797
+ .highlight (anchor->getSourceRange ());
2798
+
2799
+ for (const DiagnosticInfo &diag: errors) {
2800
+ switch (diag.reason .getKind ()) {
2801
+ case PotentialEffectReason::Kind::AsyncLet:
2802
+ if (auto declR = dyn_cast<DeclRefExpr>(&diag.expr )) {
2803
+ if (auto var = dyn_cast<VarDecl>(declR->getDecl ())) {
2804
+ if (var->isAsyncLet ()) {
2805
+ Ctx.Diags .diagnose (declR->getLoc (),
2806
+ diag::async_let_without_await,
2807
+ var->getName ());
2808
+ continue ;
2809
+ }
2810
+ }
2811
+ }
2812
+ LLVM_FALLTHROUGH; // fallthrough to a message about PropertyAccess
2813
+ case PotentialEffectReason::Kind::PropertyAccess:
2814
+ Ctx.Diags .diagnose (diag.expr .getStartLoc (),
2815
+ diag::async_access_without_await, 1 );
2816
+ continue ;
2817
+
2818
+ case PotentialEffectReason::Kind::SubscriptAccess:
2819
+ Ctx.Diags .diagnose (diag.expr .getStartLoc (),
2820
+ diag::async_access_without_await, 2 );
2821
+ continue ;
2822
+
2823
+ case PotentialEffectReason::Kind::ByClosure:
2824
+ case PotentialEffectReason::Kind::ByDefaultClosure:
2825
+ case PotentialEffectReason::Kind::ByConformance:
2826
+ case PotentialEffectReason::Kind::Apply: {
2827
+ if (auto autoclosure = dyn_cast<AutoClosureExpr>(anchor)) {
2828
+ switch (autoclosure->getThunkKind ()) {
2829
+ case AutoClosureExpr::Kind::None:
2830
+ Ctx.Diags .diagnose (diag.expr .getStartLoc (),
2831
+ diag::async_call_without_await_in_autoclosure);
2832
+ break ;
2833
+ case AutoClosureExpr::Kind::AsyncLet:
2834
+ Ctx.Diags .diagnose (diag.expr .getStartLoc (),
2835
+ diag::async_call_without_await_in_async_let);
2836
+ break ;
2837
+ case AutoClosureExpr::Kind::SingleCurryThunk:
2838
+ case AutoClosureExpr::Kind::DoubleCurryThunk:
2839
+ Ctx.Diags .diagnose (diag.expr .getStartLoc (),
2840
+ diag::async_access_without_await, 0 );
2841
+ break ;
2842
+ }
2843
+ continue ;
2844
+ }
2845
+ Ctx.Diags .diagnose (diag.expr .getStartLoc (),
2846
+ diag::async_access_without_await, 0 );
2847
+
2848
+ continue ;
2849
+ }
2850
+ }
2851
+ }
2852
+ }
2791
2853
};
2792
2854
2793
2855
// Find nested functions and perform effects checking on them.
0 commit comments