@@ -1907,67 +1907,6 @@ class Context {
19071907 }
19081908 }
19091909
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-
19711910 void diagnoseAsyncInIllegalContext (DiagnosticEngine &Diags, ASTNode node) {
19721911 if (auto *e = node.dyn_cast <Expr*>()) {
19731912 if (isa<ApplyExpr>(e)) {
@@ -2119,8 +2058,43 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
21192058 // / context.
21202059 ConditionalEffectKind MaxThrowingKind;
21212060
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;
21222076 llvm::DenseMap<Expr *, Expr *> parentMap;
21232077
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+
21242098 void flagInvalidCode () {
21252099 // Suppress warnings about useless try or catch.
21262100 Flags.set (ContextFlags::HasAnyThrowSite);
@@ -2282,6 +2256,13 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
22822256 }
22832257 }
22842258
2259+ ~CheckEffectsCoverage () {
2260+ for (Expr *anchor: errorOrder) {
2261+ diagnoseUncoveredAsyncSite (anchor);
2262+ }
2263+ }
2264+
2265+
22852266 // / Mark that the current context is top-level code with
22862267 // / throw-without-try enabled.
22872268 void setTopLevelThrowWithoutTry () {
@@ -2638,8 +2619,17 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
26382619 }
26392620 // Diagnose async calls that are outside of an await context.
26402621 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 ());
26432633 }
26442634 }
26452635
@@ -2788,6 +2778,78 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
27882778
27892779 return ShouldRecurse;
27902780 }
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+ }
27912853};
27922854
27932855// Find nested functions and perform effects checking on them.
0 commit comments