@@ -702,6 +702,18 @@ class ApplyClassifier {
702702 }
703703 }
704704
705+ Classification classifyConformance (ProtocolConformanceRef conformanceRef,
706+ EffectKind kind) {
707+ if (conformanceRef.hasEffect (kind)) {
708+ // FIXME: Should be ::Always if its not one of our
709+ // input conformances
710+ return Classification::forConditional (kind,
711+ PotentialEffectReason::forConformance ());
712+ }
713+
714+ return Classification ();
715+ }
716+
705717 // / Check to see if the given function application throws or is async.
706718 Classification classifyApply (ApplyExpr *E) {
707719 if (isa<SelfApplyExpr>(E))
@@ -747,13 +759,8 @@ class ApplyClassifier {
747759 switch (fnRef.getPolymorphicEffectKind (kind)) {
748760 case PolymorphicEffectKind::ByConformance: {
749761 auto substitutions = fnRef.getSubstitutions ();
750- for (auto conformanceRef : substitutions.getConformances ()) {
751- if (conformanceRef.hasEffect (kind)) {
752- result.merge (Classification::forConditional (kind,
753- PotentialEffectReason::forConformance ()));
754- return ;
755- }
756- }
762+ for (auto conformanceRef : substitutions.getConformances ())
763+ result.merge (classifyConformance (conformanceRef, kind));
757764
758765 // 'ByConformance' is a superset of 'ByClosure', so check for
759766 // closure arguments too.
@@ -865,8 +872,8 @@ class ApplyClassifier {
865872
866873 // If we're currently doing rethrows-checking on the body of the
867874 // function which declares the parameter, it's rethrowing-only.
868- if (kind == EffectKind::Throws &&
869- param->getDeclContext () == RethrowsDC )
875+ auto *ParentDC = getPolymorphicEffectDeclContext (kind);
876+ if (ParentDC == param->getDeclContext ())
870877 return Classification::forConditional (kind, reason);
871878
872879 // Otherwise, it throws unconditionally.
@@ -991,6 +998,18 @@ class ApplyClassifier {
991998 return ShouldRecurse;
992999 }
9931000
1001+ ShouldRecurse_t checkForEach (ForEachStmt *S) {
1002+ if (S->getTryLoc ().isValid ()) {
1003+ auto classification = Self.classifyConformance (
1004+ S->getSequenceConformance (), EffectKind::Throws);
1005+ IsInvalid |= classification.isInvalid ();
1006+ ThrowKind = std::max (ThrowKind,
1007+ classification.getConditionalKind (EffectKind::Throws));
1008+ }
1009+
1010+ return ShouldRecurse;
1011+ }
1012+
9941013 ConditionalEffectKind checkExhaustiveDoBody (DoCatchStmt *S) {
9951014 // All errors thrown by the do body are caught, but any errors thrown
9961015 // by the catch bodies are bounded by the throwing kind of the do body.
@@ -1086,6 +1105,19 @@ class ApplyClassifier {
10861105 ShouldRecurse_t checkDoCatch (DoCatchStmt *S) {
10871106 return ShouldRecurse;
10881107 }
1108+
1109+ ShouldRecurse_t checkForEach (ForEachStmt *S) {
1110+ if (S->getAwaitLoc ().isValid ()) {
1111+ auto classification = Self.classifyConformance (
1112+ S->getSequenceConformance (),
1113+ EffectKind::Async);
1114+ IsInvalid |= classification.isInvalid ();
1115+ AsyncKind = std::max (AsyncKind,
1116+ classification.getConditionalKind (EffectKind::Async));
1117+ }
1118+
1119+ return ShouldRecurse;
1120+ }
10891121 };
10901122
10911123 Optional<ConditionalEffectKind>
@@ -1325,22 +1357,43 @@ class Context {
13251357 }
13261358
13271359 // / Whether this is a function that rethrows.
1328- bool isRethrows () const {
1329- if (!HandlesErrors)
1330- return false ;
1331-
1332- if (ErrorHandlingIgnoresFunction)
1333- return false ;
1334-
1360+ bool hasPolymorphicEffect (EffectKind kind) const {
13351361 if (!Function)
13361362 return false ;
13371363
13381364 auto fn = Function->getAbstractFunctionDecl ();
13391365 if (!fn)
13401366 return false ;
13411367
1342- return fn->getPolymorphicEffectKind (EffectKind::Throws)
1343- == PolymorphicEffectKind::ByClosure;
1368+ switch (kind) {
1369+ case EffectKind::Throws:
1370+ if (!HandlesErrors)
1371+ return false ;
1372+
1373+ if (ErrorHandlingIgnoresFunction)
1374+ return false ;
1375+
1376+ break ;
1377+
1378+ case EffectKind::Async:
1379+ if (!HandlesAsync)
1380+ return false ;
1381+
1382+ break ;
1383+ }
1384+
1385+ switch (fn->getPolymorphicEffectKind (kind)) {
1386+ case PolymorphicEffectKind::ByClosure:
1387+ case PolymorphicEffectKind::ByConformance:
1388+ return true ;
1389+
1390+ case PolymorphicEffectKind::None:
1391+ case PolymorphicEffectKind::Always:
1392+ case PolymorphicEffectKind::Invalid:
1393+ return false ;
1394+ }
1395+
1396+ llvm_unreachable (" Bad polymorphic effect kind" );
13441397 }
13451398
13461399 // / Whether this is an autoclosure.
@@ -1450,9 +1503,6 @@ class Context {
14501503
14511504 Kind getKind () const { return TheKind; }
14521505
1453- bool handlesNothing () const {
1454- return !HandlesErrors;
1455- }
14561506 bool handlesThrows (ConditionalEffectKind errorKind) const {
14571507 switch (errorKind) {
14581508 case ConditionalEffectKind::None:
@@ -1465,17 +1515,30 @@ class Context {
14651515 // An operation that always throws can only be handled by an
14661516 // all-handling context.
14671517 case ConditionalEffectKind::Always:
1468- return HandlesErrors && !isRethrows ( );
1518+ return HandlesErrors && !hasPolymorphicEffect (EffectKind::Throws );
14691519 }
14701520 llvm_unreachable (" bad error kind" );
14711521 }
14721522
1473- bool handlesAsync () const {
1474- return HandlesAsync;
1523+ bool handlesAsync (ConditionalEffectKind errorKind) const {
1524+ switch (errorKind) {
1525+ case ConditionalEffectKind::None:
1526+ return true ;
1527+
1528+ // A call that's rethrowing-only can be handled by 'rethrows'.
1529+ case ConditionalEffectKind::Conditional:
1530+ return HandlesAsync;
1531+
1532+ // An operation that always throws can only be handled by an
1533+ // all-handling context.
1534+ case ConditionalEffectKind::Always:
1535+ return HandlesAsync && !hasPolymorphicEffect (EffectKind::Async);
1536+ }
1537+ llvm_unreachable (" bad error kind" );
14751538 }
14761539
1477- DeclContext *getRethrowsDC ( ) const {
1478- if (!isRethrows ( ))
1540+ DeclContext *getPolymorphicEffectDeclContext (EffectKind kind ) const {
1541+ if (!hasPolymorphicEffect (kind ))
14791542 return nullptr ;
14801543
14811544 return Function->getAbstractFunctionDecl ();
@@ -1585,8 +1648,10 @@ class Context {
15851648
15861649 // Allow the diagnostic to fire on the 'try' if we don't have
15871650 // anything else to say.
1588- if (isTryCovered && !reason.hasPolymorphicEffect () &&
1589- !isRethrows () && !isAutoClosure ()) {
1651+ if (isTryCovered &&
1652+ !reason.hasPolymorphicEffect () &&
1653+ !hasPolymorphicEffect (EffectKind::Throws) &&
1654+ !isAutoClosure ()) {
15901655 DiagnoseErrorOnTry = true ;
15911656 return ;
15921657 }
@@ -1618,7 +1683,7 @@ class Context {
16181683 return ;
16191684 }
16201685
1621- if (isRethrows ( )) {
1686+ if (hasPolymorphicEffect (EffectKind::Throws )) {
16221687 diagnoseThrowInLegalContext (Diags, E, isTryCovered, reason,
16231688 diag::throwing_call_in_rethrows_function,
16241689 diag::tryless_throwing_call_in_rethrows_function);
@@ -1657,7 +1722,7 @@ class Context {
16571722 return ;
16581723 }
16591724
1660- if (isRethrows ( )) {
1725+ if (hasPolymorphicEffect (EffectKind::Throws )) {
16611726 Diags.diagnose (S->getStartLoc (), diag::throw_in_rethrows_function);
16621727 return ;
16631728 }
@@ -1831,6 +1896,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
18311896 ASTContext &Ctx;
18321897
18331898 DeclContext *RethrowsDC = nullptr ;
1899+ DeclContext *ReasyncDC = nullptr ;
18341900 Context CurContext;
18351901
18361902 class ContextFlags {
@@ -1917,13 +1983,15 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
19171983 CheckEffectsCoverage &Self;
19181984 Context OldContext;
19191985 DeclContext *OldRethrowsDC;
1986+ DeclContext *OldReasyncDC;
19201987 ContextFlags OldFlags;
19211988 ConditionalEffectKind OldMaxThrowingKind;
19221989
19231990 public:
19241991 ContextScope (CheckEffectsCoverage &self, Optional<Context> newContext)
19251992 : Self(self), OldContext(self.CurContext),
19261993 OldRethrowsDC (self.RethrowsDC),
1994+ OldReasyncDC(self.ReasyncDC),
19271995 OldFlags(self.Flags),
19281996 OldMaxThrowingKind(self.MaxThrowingKind) {
19291997 if (newContext) self.CurContext = *newContext;
@@ -1934,6 +2002,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
19342002
19352003 void enterSubFunction () {
19362004 Self.RethrowsDC = nullptr ;
2005+ Self.ReasyncDC = nullptr ;
19372006 }
19382007
19392008 void enterTry () {
@@ -2038,6 +2107,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
20382107 ~ContextScope () {
20392108 Self.CurContext = OldContext;
20402109 Self.RethrowsDC = OldRethrowsDC;
2110+ Self.ReasyncDC = OldReasyncDC;
20412111 Self.Flags = OldFlags;
20422112 Self.MaxThrowingKind = OldMaxThrowingKind;
20432113 }
@@ -2048,9 +2118,14 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
20482118 : Ctx(ctx), CurContext(initialContext),
20492119 MaxThrowingKind (ConditionalEffectKind::None) {
20502120
2051- if (auto rethrowsDC = initialContext.getRethrowsDC ()) {
2121+ if (auto rethrowsDC = initialContext.getPolymorphicEffectDeclContext (
2122+ EffectKind::Throws)) {
20522123 RethrowsDC = rethrowsDC;
20532124 }
2125+ if (auto reasyncDC = initialContext.getPolymorphicEffectDeclContext (
2126+ EffectKind::Async)) {
2127+ ReasyncDC = reasyncDC;
2128+ }
20542129 }
20552130
20562131 // / Mark that the current context is top-level code with
@@ -2131,7 +2206,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
21312206
21322207 // If the enclosing context doesn't handle anything, use a
21332208 // specialized diagnostic about non-exhaustive catches.
2134- if (CurContext.handlesNothing ( )) {
2209+ if (! CurContext.handlesThrows (ConditionalEffectKind::Conditional )) {
21352210 CurContext.setNonExhaustiveCatch (true );
21362211 }
21372212
@@ -2168,7 +2243,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
21682243
21692244 auto savedContext = CurContext;
21702245 if (doThrowingKind != ConditionalEffectKind::Always &&
2171- CurContext.isRethrows ( )) {
2246+ CurContext.hasPolymorphicEffect (EffectKind::Throws )) {
21722247 // If this catch clause is reachable at all, it's because a function
21732248 // parameter throws. So let's temporarily state that the body is allowed
21742249 // to throw.
@@ -2186,6 +2261,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
21862261 // But if the expression didn't type-check, suppress diagnostics.
21872262 ApplyClassifier classifier;
21882263 classifier.RethrowsDC = RethrowsDC;
2264+ classifier.ReasyncDC = ReasyncDC;
21892265 auto classification = classifier.classifyApply (E);
21902266
21912267 checkThrowAsyncSite (E, /* requiresTry*/ true , classification);
@@ -2243,7 +2319,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
22432319
22442320 ShouldRecurse_t checkAsyncLet (PatternBindingDecl *patternBinding) {
22452321 // Diagnose async let in a context that doesn't handle async.
2246- if (!CurContext.handlesAsync ()) {
2322+ if (!CurContext.handlesAsync (ConditionalEffectKind::Always )) {
22472323 CurContext.diagnoseUnhandledAsyncSite (Ctx.Diags , patternBinding);
22482324 }
22492325
@@ -2319,14 +2395,12 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
23192395 break ;
23202396
23212397 case ConditionalEffectKind::Conditional:
2322- llvm_unreachable (" Not supported yet\n " );
2323-
23242398 case ConditionalEffectKind::Always:
23252399 // Remember that we've seen an async call.
23262400 Flags.set (ContextFlags::HasAnyAsyncSite);
23272401
23282402 // Diagnose async calls in a context that doesn't handle async.
2329- if (!CurContext.handlesAsync ()) {
2403+ if (!CurContext.handlesAsync (asyncKind )) {
23302404 CurContext.diagnoseUnhandledAsyncSite (Ctx.Diags , E);
23312405 }
23322406 // Diagnose async calls that are outside of an await context.
@@ -2382,7 +2456,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
23822456 // course we're in a context that could never handle an 'async'. Then, we
23832457 // produce an error.
23842458 if (!Flags.has (ContextFlags::HasAnyAsyncSite)) {
2385- if (CurContext.handlesAsync ())
2459+ if (CurContext.handlesAsync (ConditionalEffectKind::Conditional ))
23862460 Ctx.Diags .diagnose (E->getAwaitLoc (), diag::no_async_in_await);
23872461 else
23882462 CurContext.diagnoseUnhandledAsyncSite (Ctx.Diags , E);
@@ -2407,7 +2481,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
24072481
24082482 // Diagnose all the call sites within a single unhandled 'try'
24092483 // at the same time.
2410- } else if (CurContext.handlesNothing ( )) {
2484+ } else if (! CurContext.handlesThrows (ConditionalEffectKind::Conditional )) {
24112485 CurContext.diagnoseUnhandledTry (Ctx.Diags , E);
24122486 }
24132487
@@ -2448,16 +2522,27 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
24482522 }
24492523
24502524 ShouldRecurse_t checkForEach (ForEachStmt *S) {
2451- // FIXME: Handle 'for try await' inside a 'rethrows'-by-conformance
2452- // function
2453- if (S->getTryLoc ().isValid () &&
2454- !CurContext.handlesThrows (ConditionalEffectKind::Always)) {
2455- CurContext.diagnoseUnhandledThrowStmt (Ctx.Diags , S);
2525+ if (!S->getAwaitLoc ().isValid ())
2526+ return ShouldRecurse;
2527+
2528+ ApplyClassifier classifier;
2529+ classifier.RethrowsDC = RethrowsDC;
2530+ classifier.ReasyncDC = ReasyncDC;
2531+
2532+ if (S->getTryLoc ().isValid ()) {
2533+ auto classification = classifier.classifyConformance (
2534+ S->getSequenceConformance (), EffectKind::Throws);
2535+ auto throwsKind = classification.getConditionalKind (EffectKind::Throws);
2536+ if (!CurContext.handlesThrows (throwsKind))
2537+ CurContext.diagnoseUnhandledThrowStmt (Ctx.Diags , S);
24562538 }
2457- if (S->getAwaitLoc ().isValid () &&
2458- !CurContext.handlesAsync ()) {
2539+
2540+ auto classification = classifier.classifyConformance (
2541+ S->getSequenceConformance (), EffectKind::Async);
2542+ auto asyncKind = classification.getConditionalKind (EffectKind::Async);
2543+ if (!CurContext.handlesAsync (asyncKind))
24592544 CurContext.diagnoseUnhandledAsyncSite (Ctx.Diags , S);
2460- }
2545+
24612546 return ShouldRecurse;
24622547 }
24632548};
0 commit comments