@@ -686,9 +686,19 @@ namespace {
686
686
// Returns the result of subtracting the other space from this space. The
687
687
// result is empty if the other space completely covers this space, or
688
688
// non-empty if there were any uncovered cases. The difference of spaces
689
- // is the smallest uncovered set of cases.
690
- Space minus (const Space &other, TypeChecker &TC,
691
- const DeclContext *DC) const {
689
+ // is the smallest uncovered set of cases. The result is absent if the
690
+ // computation had to be abandoned.
691
+ //
692
+ // \p minusCount is an optional pointer counting the number of
693
+ // times minus has run.
694
+ // Returns None if the computation "timed out".
695
+ Optional<Space> minus (const Space &other, TypeChecker &TC,
696
+ const DeclContext *DC, unsigned *minusCount) const {
697
+
698
+ if (minusCount && TC.getSwitchCheckingInvocationThreshold () &&
699
+ (*minusCount)++ >= TC.getSwitchCheckingInvocationThreshold ())
700
+ return None;
701
+
692
702
if (this ->isEmpty ()) {
693
703
return Space ();
694
704
}
@@ -719,7 +729,7 @@ namespace {
719
729
SmallVector<Space, 4 > spaces;
720
730
this ->decompose (TC, DC, this ->getType (), spaces);
721
731
auto decomp = Space::forDisjunct (spaces);
722
- return decomp.minus (other, TC, DC);
732
+ return decomp.minus (other, TC, DC, minusCount );
723
733
} else {
724
734
return *this ;
725
735
}
@@ -738,12 +748,14 @@ namespace {
738
748
PAIRCASE (SpaceKind::Disjunct, SpaceKind::Disjunct):
739
749
PAIRCASE (SpaceKind::BooleanConstant, SpaceKind::Disjunct):
740
750
PAIRCASE (SpaceKind::UnknownCase, SpaceKind::Disjunct): {
741
- return std::accumulate (other.getSpaces ().begin (),
742
- other.getSpaces ().end (),
743
- *this ,
744
- [&](const Space &left, const Space &right){
745
- return left.minus (right, TC, DC);
746
- });
751
+ Space tot = *this ;
752
+ for (auto s : other.getSpaces ()) {
753
+ if (auto diff = tot.minus (s, TC, DC, minusCount))
754
+ tot = *diff;
755
+ else
756
+ return None;
757
+ }
758
+ return tot;
747
759
}
748
760
749
761
PAIRCASE (SpaceKind::Disjunct, SpaceKind::Empty):
@@ -752,19 +764,23 @@ namespace {
752
764
PAIRCASE (SpaceKind::Disjunct, SpaceKind::BooleanConstant):
753
765
PAIRCASE (SpaceKind::Disjunct, SpaceKind::UnknownCase): {
754
766
SmallVector<Space, 4 > smallSpaces;
755
- std::transform (this ->getSpaces ().begin (), this ->getSpaces ().end (),
756
- std::back_inserter (smallSpaces),
757
- [&](const Space &first){
758
- return first.minus (other, TC, DC);
759
- });
767
+ for (auto s : this ->getSpaces ()) {
768
+ if (auto diff = s.minus (other, TC, DC, minusCount))
769
+ smallSpaces.push_back (*diff);
770
+ else
771
+ return None;
772
+ }
760
773
return Space::forDisjunct (smallSpaces);
761
774
}
762
775
PAIRCASE (SpaceKind::Constructor, SpaceKind::Type):
763
776
return Space ();
764
777
PAIRCASE (SpaceKind::Constructor, SpaceKind::UnknownCase): {
765
778
SmallVector<Space, 4 > newSubSpaces;
766
779
for (auto subSpace : this ->getSpaces ()) {
767
- Space nextSpace = subSpace.minus (other, TC, DC).simplify (TC, DC);
780
+ auto diff = subSpace.minus (other, TC, DC, minusCount);
781
+ if (!diff)
782
+ return None;
783
+ auto nextSpace = diff->simplify (TC, DC);
768
784
if (nextSpace.isEmpty ())
769
785
return Space ();
770
786
newSubSpaces.push_back (nextSpace);
@@ -813,7 +829,11 @@ namespace {
813
829
SmallVector<Space, 4 > copyParams (this ->getSpaces ().begin (),
814
830
this ->getSpaces ().end ());
815
831
816
- auto reducedSpace = s1.minus (s2, TC, DC);
832
+ auto reducedSpaceOrNone = s1.minus (s2, TC, DC, minusCount);
833
+ if (!reducedSpaceOrNone)
834
+ return None;
835
+ auto reducedSpace = *reducedSpaceOrNone;
836
+
817
837
// If one of the constructor parameters is empty it means
818
838
// the whole constructor space is empty as well, so we can
819
839
// safely skip it.
@@ -857,7 +877,7 @@ namespace {
857
877
SmallVector<Space, 4 > spaces;
858
878
this ->decompose (TC, DC, other.getType (), spaces);
859
879
auto disjunctSp = Space::forDisjunct (spaces);
860
- return this ->minus (disjunctSp, TC, DC);
880
+ return this ->minus (disjunctSp, TC, DC, minusCount );
861
881
}
862
882
return *this ;
863
883
}
@@ -871,7 +891,7 @@ namespace {
871
891
SmallVector<Space, 4 > spaces;
872
892
this ->decompose (TC, DC, this ->getType (), spaces);
873
893
auto orSpace = Space::forDisjunct (spaces);
874
- return orSpace.minus (other, TC, DC);
894
+ return orSpace.minus (other, TC, DC, minusCount );
875
895
} else {
876
896
return *this ;
877
897
}
@@ -1286,26 +1306,21 @@ namespace {
1286
1306
Space totalSpace = Space::forType (subjectType, Identifier ());
1287
1307
Space coveredSpace = Space::forDisjunct (spaces);
1288
1308
1289
- size_t totalSpaceSize = totalSpace.getSize (TC, DC);
1309
+ const size_t totalSpaceSize = totalSpace.getSize (TC, DC);
1290
1310
if (totalSpaceSize > Space::getMaximumSize ()) {
1291
- // Because the space is large, we have to extend the size
1292
- // heuristic to compensate for actually exhaustively pattern matching
1293
- // over enormous spaces. In this case, if the covered space covers
1294
- // as much as the total space, and there were no duplicates, then we
1295
- // can assume the user did the right thing and that they don't need
1296
- // a 'default' to be inserted.
1297
- // FIXME: Do something sensible for non-frozen enums.
1298
- if (!sawRedundantPattern
1299
- && coveredSpace.getSize (TC, DC) >= totalSpaceSize) {
1300
- return ;
1301
- }
1302
-
1303
- diagnoseMissingCases (RequiresDefault::SpaceTooLarge, Space (),
1304
- unknownCase);
1311
+ diagnoseCannotCheck (sawRedundantPattern, totalSpaceSize, coveredSpace,
1312
+ unknownCase);
1305
1313
return ;
1306
1314
}
1307
-
1308
- auto uncovered = totalSpace.minus (coveredSpace, TC, DC).simplify (TC, DC);
1315
+ unsigned minusCount = 0 ;
1316
+ auto diff = totalSpace.minus (coveredSpace, TC, DC, &minusCount);
1317
+ if (!diff) {
1318
+ diagnoseCannotCheck (sawRedundantPattern, totalSpaceSize, coveredSpace,
1319
+ unknownCase);
1320
+ return ;
1321
+ }
1322
+
1323
+ auto uncovered = diff->simplify (TC, DC);
1309
1324
if (unknownCase && uncovered.isEmpty ()) {
1310
1325
TC.diagnose (unknownCase->getLoc (), diag::redundant_particular_case)
1311
1326
.highlight (unknownCase->getSourceRange ());
@@ -1314,8 +1329,8 @@ namespace {
1314
1329
// Account for unknown cases. If the developer wrote `unknown`, they're
1315
1330
// all handled; otherwise, we ignore the ones that were added for enums
1316
1331
// that are implicitly frozen.
1317
- uncovered = uncovered.minus (Space::forUnknown (unknownCase == nullptr ),
1318
- TC, DC);
1332
+ uncovered = * uncovered.minus (Space::forUnknown (unknownCase == nullptr ),
1333
+ TC, DC, /* &minusCount */ nullptr );
1319
1334
uncovered = uncovered.simplify (TC, DC);
1320
1335
1321
1336
if (uncovered.isEmpty ())
@@ -1350,9 +1365,27 @@ namespace {
1350
1365
UncoveredSwitch,
1351
1366
SpaceTooLarge,
1352
1367
};
1353
-
1354
- void diagnoseMissingCases (const RequiresDefault defaultReason,
1355
- Space uncovered,
1368
+
1369
+ void diagnoseCannotCheck (const bool sawRedundantPattern,
1370
+ const size_t totalSpaceSize,
1371
+ const Space &coveredSpace,
1372
+ const CaseStmt *unknownCase) {
1373
+ // Because the space is large or the check is too slow,
1374
+ // we have to extend the size
1375
+ // heuristic to compensate for actually exhaustively pattern matching
1376
+ // over enormous spaces. In this case, if the covered space covers
1377
+ // as much as the total space, and there were no duplicates, then we
1378
+ // can assume the user did the right thing and that they don't need
1379
+ // a 'default' to be inserted.
1380
+ // FIXME: Do something sensible for non-frozen enums.
1381
+ if (!sawRedundantPattern &&
1382
+ coveredSpace.getSize (TC, DC) >= totalSpaceSize)
1383
+ return ;
1384
+ diagnoseMissingCases (RequiresDefault::SpaceTooLarge, Space (),
1385
+ unknownCase);
1386
+ }
1387
+
1388
+ void diagnoseMissingCases (RequiresDefault defaultReason, Space uncovered,
1356
1389
const CaseStmt *unknownCase = nullptr ,
1357
1390
bool sawDowngradablePattern = false ) {
1358
1391
SourceLoc startLoc = Switch->getStartLoc ();
0 commit comments