@@ -686,9 +686,19 @@ namespace {
686686 // Returns the result of subtracting the other space from this space. The
687687 // result is empty if the other space completely covers this space, or
688688 // 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+
692702 if (this ->isEmpty ()) {
693703 return Space ();
694704 }
@@ -719,7 +729,7 @@ namespace {
719729 SmallVector<Space, 4 > spaces;
720730 this ->decompose (TC, DC, this ->getType (), spaces);
721731 auto decomp = Space::forDisjunct (spaces);
722- return decomp.minus (other, TC, DC);
732+ return decomp.minus (other, TC, DC, minusCount );
723733 } else {
724734 return *this ;
725735 }
@@ -738,12 +748,14 @@ namespace {
738748 PAIRCASE (SpaceKind::Disjunct, SpaceKind::Disjunct):
739749 PAIRCASE (SpaceKind::BooleanConstant, SpaceKind::Disjunct):
740750 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;
747759 }
748760
749761 PAIRCASE (SpaceKind::Disjunct, SpaceKind::Empty):
@@ -752,19 +764,23 @@ namespace {
752764 PAIRCASE (SpaceKind::Disjunct, SpaceKind::BooleanConstant):
753765 PAIRCASE (SpaceKind::Disjunct, SpaceKind::UnknownCase): {
754766 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+ }
760773 return Space::forDisjunct (smallSpaces);
761774 }
762775 PAIRCASE (SpaceKind::Constructor, SpaceKind::Type):
763776 return Space ();
764777 PAIRCASE (SpaceKind::Constructor, SpaceKind::UnknownCase): {
765778 SmallVector<Space, 4 > newSubSpaces;
766779 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);
768784 if (nextSpace.isEmpty ())
769785 return Space ();
770786 newSubSpaces.push_back (nextSpace);
@@ -813,7 +829,11 @@ namespace {
813829 SmallVector<Space, 4 > copyParams (this ->getSpaces ().begin (),
814830 this ->getSpaces ().end ());
815831
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+
817837 // If one of the constructor parameters is empty it means
818838 // the whole constructor space is empty as well, so we can
819839 // safely skip it.
@@ -857,7 +877,7 @@ namespace {
857877 SmallVector<Space, 4 > spaces;
858878 this ->decompose (TC, DC, other.getType (), spaces);
859879 auto disjunctSp = Space::forDisjunct (spaces);
860- return this ->minus (disjunctSp, TC, DC);
880+ return this ->minus (disjunctSp, TC, DC, minusCount );
861881 }
862882 return *this ;
863883 }
@@ -871,7 +891,7 @@ namespace {
871891 SmallVector<Space, 4 > spaces;
872892 this ->decompose (TC, DC, this ->getType (), spaces);
873893 auto orSpace = Space::forDisjunct (spaces);
874- return orSpace.minus (other, TC, DC);
894+ return orSpace.minus (other, TC, DC, minusCount );
875895 } else {
876896 return *this ;
877897 }
@@ -1286,26 +1306,21 @@ namespace {
12861306 Space totalSpace = Space::forType (subjectType, Identifier ());
12871307 Space coveredSpace = Space::forDisjunct (spaces);
12881308
1289- size_t totalSpaceSize = totalSpace.getSize (TC, DC);
1309+ const size_t totalSpaceSize = totalSpace.getSize (TC, DC);
12901310 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);
13051313 return ;
13061314 }
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);
13091324 if (unknownCase && uncovered.isEmpty ()) {
13101325 TC.diagnose (unknownCase->getLoc (), diag::redundant_particular_case)
13111326 .highlight (unknownCase->getSourceRange ());
@@ -1314,8 +1329,8 @@ namespace {
13141329 // Account for unknown cases. If the developer wrote `unknown`, they're
13151330 // all handled; otherwise, we ignore the ones that were added for enums
13161331 // 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 );
13191334 uncovered = uncovered.simplify (TC, DC);
13201335
13211336 if (uncovered.isEmpty ())
@@ -1350,9 +1365,27 @@ namespace {
13501365 UncoveredSwitch,
13511366 SpaceTooLarge,
13521367 };
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,
13561389 const CaseStmt *unknownCase = nullptr ,
13571390 bool sawDowngradablePattern = false ) {
13581391 SourceLoc startLoc = Switch->getStartLoc ();
0 commit comments