Skip to content

Commit 8990bd0

Browse files
committed
Stricter enforcement of the "large space" heuristic
The Space Engine includes a heuristic that attempted a combinatorics- based check to see if a pattern covered an insufficient amount of cases. In straight-line switches this avoided computing a subspace match that would have been quite expensive computationally. However, when expressive patterns (like tuple patterns) are used, it can fool the check because the covered space is much larger than the actual size of the space due to pattern overlap that counting like this simply can't detect. Instead, just do the right thing and perform a space subtraction after the existing preconditions for the heuristic are satisfied. Resolves SR-6316
1 parent 837ff19 commit 8990bd0

File tree

2 files changed

+32
-8
lines changed

2 files changed

+32
-8
lines changed

lib/Sema/TypeCheckSwitchStmt.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,23 +1063,25 @@ namespace {
10631063

10641064
Space totalSpace(subjectType, Identifier());
10651065
Space coveredSpace(spaces);
1066+
10661067
size_t totalSpaceSize = totalSpace.getSize(TC);
10671068
if (totalSpaceSize > Space::getMaximumSize()) {
1068-
// Because the space is large, we have to extend the size
1069-
// heuristic to compensate for actually exhaustively pattern matching
1070-
// over enormous spaces. In this case, if the covered space covers
1071-
// as much as the total space, and there were no duplicates, then we
1072-
// can assume the user did the right thing and that they don't need
1073-
// a 'default' to be inserted.
1069+
// Because the space is large, fall back to a heuristic that rejects
1070+
// the common case of providing an insufficient number of covering
1071+
// patterns. We still need to fall back to space subtraction if the
1072+
// covered space is larger than the total space because there is
1073+
// necessarily overlap in the pattern matrix that can't be detected
1074+
// by combinatorics alone.
10741075
if (!sawRedundantPattern
1075-
&& coveredSpace.getSize(TC) >= totalSpaceSize) {
1076+
&& coveredSpace.getSize(TC) >= totalSpaceSize
1077+
&& totalSpace.minus(coveredSpace, TC).simplify(TC).isEmpty()) {
10761078
return;
10771079
}
10781080

10791081
diagnoseMissingCases(TC, Switch, /*justNeedsDefault*/true, Space());
10801082
return;
10811083
}
1082-
1084+
10831085
auto uncovered = totalSpace.minus(coveredSpace, TC).simplify(TC);
10841086
if (uncovered.isEmpty()) {
10851087
return;

test/Sema/exhaustive_switch.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,28 @@ func infinitelySized() -> Bool {
559559
}
560560
}
561561

562+
// SR-6316: Size heuristic is insufficient to catch space covering when the
563+
// covered space size is greater than or equal to the master space size.
564+
func largeSpaceMatch(_ x: Bool) {
565+
switch (x, (x, x, x, x), (x, x, x, x)) { // expected-error {{switch must be exhaustive}}
566+
// expected-note@-1 {{do you want to add a default clause?}}
567+
case (true, (_, _, _, _), (_, true, true, _)):
568+
break
569+
case (true, (_, _, _, _), (_, _, false, _)):
570+
break
571+
case (_, (_, true, true, _), (_, _, false, _)):
572+
break
573+
case (_, (_, _, false, _), (_, true, true, _)):
574+
break
575+
case (_, (_, true, true, _), (_, true, true, _)):
576+
break
577+
case (_, (_, _, false, _), (_, _, false, _)):
578+
break
579+
case (_, (false, false, false, false), (_, _, _, _)):
580+
break
581+
}
582+
}
583+
562584
func diagnoseDuplicateLiterals() {
563585
let str = "def"
564586
let int = 2

0 commit comments

Comments
 (0)