@@ -702,6 +702,18 @@ class ApplyClassifier {
702
702
}
703
703
}
704
704
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
+
705
717
// / Check to see if the given function application throws or is async.
706
718
Classification classifyApply (ApplyExpr *E) {
707
719
if (isa<SelfApplyExpr>(E))
@@ -747,13 +759,8 @@ class ApplyClassifier {
747
759
switch (fnRef.getPolymorphicEffectKind (kind)) {
748
760
case PolymorphicEffectKind::ByConformance: {
749
761
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));
757
764
758
765
// 'ByConformance' is a superset of 'ByClosure', so check for
759
766
// closure arguments too.
@@ -865,8 +872,8 @@ class ApplyClassifier {
865
872
866
873
// If we're currently doing rethrows-checking on the body of the
867
874
// 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 ())
870
877
return Classification::forConditional (kind, reason);
871
878
872
879
// Otherwise, it throws unconditionally.
@@ -991,6 +998,18 @@ class ApplyClassifier {
991
998
return ShouldRecurse;
992
999
}
993
1000
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
+
994
1013
ConditionalEffectKind checkExhaustiveDoBody (DoCatchStmt *S) {
995
1014
// All errors thrown by the do body are caught, but any errors thrown
996
1015
// by the catch bodies are bounded by the throwing kind of the do body.
@@ -1086,6 +1105,19 @@ class ApplyClassifier {
1086
1105
ShouldRecurse_t checkDoCatch (DoCatchStmt *S) {
1087
1106
return ShouldRecurse;
1088
1107
}
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
+ }
1089
1121
};
1090
1122
1091
1123
Optional<ConditionalEffectKind>
@@ -1325,22 +1357,43 @@ class Context {
1325
1357
}
1326
1358
1327
1359
// / 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 {
1335
1361
if (!Function)
1336
1362
return false ;
1337
1363
1338
1364
auto fn = Function->getAbstractFunctionDecl ();
1339
1365
if (!fn)
1340
1366
return false ;
1341
1367
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" );
1344
1397
}
1345
1398
1346
1399
// / Whether this is an autoclosure.
@@ -1450,9 +1503,6 @@ class Context {
1450
1503
1451
1504
Kind getKind () const { return TheKind; }
1452
1505
1453
- bool handlesNothing () const {
1454
- return !HandlesErrors;
1455
- }
1456
1506
bool handlesThrows (ConditionalEffectKind errorKind) const {
1457
1507
switch (errorKind) {
1458
1508
case ConditionalEffectKind::None:
@@ -1465,17 +1515,30 @@ class Context {
1465
1515
// An operation that always throws can only be handled by an
1466
1516
// all-handling context.
1467
1517
case ConditionalEffectKind::Always:
1468
- return HandlesErrors && !isRethrows ( );
1518
+ return HandlesErrors && !hasPolymorphicEffect (EffectKind::Throws );
1469
1519
}
1470
1520
llvm_unreachable (" bad error kind" );
1471
1521
}
1472
1522
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" );
1475
1538
}
1476
1539
1477
- DeclContext *getRethrowsDC ( ) const {
1478
- if (!isRethrows ( ))
1540
+ DeclContext *getPolymorphicEffectDeclContext (EffectKind kind ) const {
1541
+ if (!hasPolymorphicEffect (kind ))
1479
1542
return nullptr ;
1480
1543
1481
1544
return Function->getAbstractFunctionDecl ();
@@ -1585,8 +1648,10 @@ class Context {
1585
1648
1586
1649
// Allow the diagnostic to fire on the 'try' if we don't have
1587
1650
// anything else to say.
1588
- if (isTryCovered && !reason.hasPolymorphicEffect () &&
1589
- !isRethrows () && !isAutoClosure ()) {
1651
+ if (isTryCovered &&
1652
+ !reason.hasPolymorphicEffect () &&
1653
+ !hasPolymorphicEffect (EffectKind::Throws) &&
1654
+ !isAutoClosure ()) {
1590
1655
DiagnoseErrorOnTry = true ;
1591
1656
return ;
1592
1657
}
@@ -1618,7 +1683,7 @@ class Context {
1618
1683
return ;
1619
1684
}
1620
1685
1621
- if (isRethrows ( )) {
1686
+ if (hasPolymorphicEffect (EffectKind::Throws )) {
1622
1687
diagnoseThrowInLegalContext (Diags, E, isTryCovered, reason,
1623
1688
diag::throwing_call_in_rethrows_function,
1624
1689
diag::tryless_throwing_call_in_rethrows_function);
@@ -1657,7 +1722,7 @@ class Context {
1657
1722
return ;
1658
1723
}
1659
1724
1660
- if (isRethrows ( )) {
1725
+ if (hasPolymorphicEffect (EffectKind::Throws )) {
1661
1726
Diags.diagnose (S->getStartLoc (), diag::throw_in_rethrows_function);
1662
1727
return ;
1663
1728
}
@@ -1831,6 +1896,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
1831
1896
ASTContext &Ctx;
1832
1897
1833
1898
DeclContext *RethrowsDC = nullptr ;
1899
+ DeclContext *ReasyncDC = nullptr ;
1834
1900
Context CurContext;
1835
1901
1836
1902
class ContextFlags {
@@ -1917,13 +1983,15 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
1917
1983
CheckEffectsCoverage &Self;
1918
1984
Context OldContext;
1919
1985
DeclContext *OldRethrowsDC;
1986
+ DeclContext *OldReasyncDC;
1920
1987
ContextFlags OldFlags;
1921
1988
ConditionalEffectKind OldMaxThrowingKind;
1922
1989
1923
1990
public:
1924
1991
ContextScope (CheckEffectsCoverage &self, Optional<Context> newContext)
1925
1992
: Self(self), OldContext(self.CurContext),
1926
1993
OldRethrowsDC (self.RethrowsDC),
1994
+ OldReasyncDC(self.ReasyncDC),
1927
1995
OldFlags(self.Flags),
1928
1996
OldMaxThrowingKind(self.MaxThrowingKind) {
1929
1997
if (newContext) self.CurContext = *newContext;
@@ -1934,6 +2002,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
1934
2002
1935
2003
void enterSubFunction () {
1936
2004
Self.RethrowsDC = nullptr ;
2005
+ Self.ReasyncDC = nullptr ;
1937
2006
}
1938
2007
1939
2008
void enterTry () {
@@ -2038,6 +2107,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2038
2107
~ContextScope () {
2039
2108
Self.CurContext = OldContext;
2040
2109
Self.RethrowsDC = OldRethrowsDC;
2110
+ Self.ReasyncDC = OldReasyncDC;
2041
2111
Self.Flags = OldFlags;
2042
2112
Self.MaxThrowingKind = OldMaxThrowingKind;
2043
2113
}
@@ -2048,9 +2118,14 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2048
2118
: Ctx(ctx), CurContext(initialContext),
2049
2119
MaxThrowingKind (ConditionalEffectKind::None) {
2050
2120
2051
- if (auto rethrowsDC = initialContext.getRethrowsDC ()) {
2121
+ if (auto rethrowsDC = initialContext.getPolymorphicEffectDeclContext (
2122
+ EffectKind::Throws)) {
2052
2123
RethrowsDC = rethrowsDC;
2053
2124
}
2125
+ if (auto reasyncDC = initialContext.getPolymorphicEffectDeclContext (
2126
+ EffectKind::Async)) {
2127
+ ReasyncDC = reasyncDC;
2128
+ }
2054
2129
}
2055
2130
2056
2131
// / Mark that the current context is top-level code with
@@ -2131,7 +2206,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2131
2206
2132
2207
// If the enclosing context doesn't handle anything, use a
2133
2208
// specialized diagnostic about non-exhaustive catches.
2134
- if (CurContext.handlesNothing ( )) {
2209
+ if (! CurContext.handlesThrows (ConditionalEffectKind::Conditional )) {
2135
2210
CurContext.setNonExhaustiveCatch (true );
2136
2211
}
2137
2212
@@ -2168,7 +2243,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2168
2243
2169
2244
auto savedContext = CurContext;
2170
2245
if (doThrowingKind != ConditionalEffectKind::Always &&
2171
- CurContext.isRethrows ( )) {
2246
+ CurContext.hasPolymorphicEffect (EffectKind::Throws )) {
2172
2247
// If this catch clause is reachable at all, it's because a function
2173
2248
// parameter throws. So let's temporarily state that the body is allowed
2174
2249
// to throw.
@@ -2186,6 +2261,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2186
2261
// But if the expression didn't type-check, suppress diagnostics.
2187
2262
ApplyClassifier classifier;
2188
2263
classifier.RethrowsDC = RethrowsDC;
2264
+ classifier.ReasyncDC = ReasyncDC;
2189
2265
auto classification = classifier.classifyApply (E);
2190
2266
2191
2267
checkThrowAsyncSite (E, /* requiresTry*/ true , classification);
@@ -2243,7 +2319,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2243
2319
2244
2320
ShouldRecurse_t checkAsyncLet (PatternBindingDecl *patternBinding) {
2245
2321
// Diagnose async let in a context that doesn't handle async.
2246
- if (!CurContext.handlesAsync ()) {
2322
+ if (!CurContext.handlesAsync (ConditionalEffectKind::Always )) {
2247
2323
CurContext.diagnoseUnhandledAsyncSite (Ctx.Diags , patternBinding);
2248
2324
}
2249
2325
@@ -2319,14 +2395,12 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2319
2395
break ;
2320
2396
2321
2397
case ConditionalEffectKind::Conditional:
2322
- llvm_unreachable (" Not supported yet\n " );
2323
-
2324
2398
case ConditionalEffectKind::Always:
2325
2399
// Remember that we've seen an async call.
2326
2400
Flags.set (ContextFlags::HasAnyAsyncSite);
2327
2401
2328
2402
// Diagnose async calls in a context that doesn't handle async.
2329
- if (!CurContext.handlesAsync ()) {
2403
+ if (!CurContext.handlesAsync (asyncKind )) {
2330
2404
CurContext.diagnoseUnhandledAsyncSite (Ctx.Diags , E);
2331
2405
}
2332
2406
// Diagnose async calls that are outside of an await context.
@@ -2382,7 +2456,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2382
2456
// course we're in a context that could never handle an 'async'. Then, we
2383
2457
// produce an error.
2384
2458
if (!Flags.has (ContextFlags::HasAnyAsyncSite)) {
2385
- if (CurContext.handlesAsync ())
2459
+ if (CurContext.handlesAsync (ConditionalEffectKind::Conditional ))
2386
2460
Ctx.Diags .diagnose (E->getAwaitLoc (), diag::no_async_in_await);
2387
2461
else
2388
2462
CurContext.diagnoseUnhandledAsyncSite (Ctx.Diags , E);
@@ -2407,7 +2481,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2407
2481
2408
2482
// Diagnose all the call sites within a single unhandled 'try'
2409
2483
// at the same time.
2410
- } else if (CurContext.handlesNothing ( )) {
2484
+ } else if (! CurContext.handlesThrows (ConditionalEffectKind::Conditional )) {
2411
2485
CurContext.diagnoseUnhandledTry (Ctx.Diags , E);
2412
2486
}
2413
2487
@@ -2448,16 +2522,27 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
2448
2522
}
2449
2523
2450
2524
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);
2456
2538
}
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))
2459
2544
CurContext.diagnoseUnhandledAsyncSite (Ctx.Diags , S);
2460
- }
2545
+
2461
2546
return ShouldRecurse;
2462
2547
}
2463
2548
};
0 commit comments