Skip to content

Commit d36a739

Browse files
authored
Fix issue with expression patterns in switch exhaustivity checking (#23804)
Expression patterns (and cast patterns) don't actually contribute to the exhaustivity of a switch statement---if you're matching against a String, matching "abc" doesn't meaningfully reduce the full space of the values you have to match. This was already handled, but didn't do the right thing in a particular case involving a tuple payload in an enum after the Space Engine (exhaustivity checker) optimizations that went out in Swift 5. https://bugs.swift.org/browse/SR-10301
1 parent 16b6501 commit d36a739

File tree

3 files changed

+89
-0
lines changed

3 files changed

+89
-0
lines changed

lib/Sema/TypeCheckSwitchStmt.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,6 +1380,7 @@ namespace {
13801380
}
13811381
}
13821382
case PatternKind::Typed:
1383+
llvm_unreachable("cannot appear in case patterns");
13831384
case PatternKind::Expr:
13841385
return Space();
13851386
case PatternKind::Var: {
@@ -1428,6 +1429,8 @@ namespace {
14281429
conArgSpace);
14291430
}
14301431
case PatternKind::Paren: {
1432+
// If we've got an extra level of parens, we need to flatten that into
1433+
// the enum payload.
14311434
auto *PP = dyn_cast<ParenPattern>(SP);
14321435
auto *SP = PP->getSemanticsProvidingPattern();
14331436

@@ -1448,6 +1451,12 @@ namespace {
14481451
}
14491452
} else if (SP->getKind() == PatternKind::Tuple) {
14501453
Space argTupleSpace = projectPattern(TC, SP);
1454+
// Tuples are modeled as if they are enums with a single, nameless
1455+
// case, which means argTupleSpace will either be a Constructor or
1456+
// Empty space. If it's empty (i.e. it contributes nothing to the
1457+
// overall exhaustiveness), the entire enum case space is empty.
1458+
if (argTupleSpace.isEmpty())
1459+
return Space();
14511460
assert(argTupleSpace.getKind() == SpaceKind::Constructor);
14521461
conArgSpace.insert(conArgSpace.end(),
14531462
argTupleSpace.getSpaces().begin(),

test/Compatibility/exhaustive_switch.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,3 +1176,43 @@ extension Result where T == NoError {
11761176
}
11771177
}
11781178
}
1179+
1180+
enum SR10301<T,E> {
1181+
case value(T)
1182+
case error(E)
1183+
}
1184+
enum SR10301Error: Error {
1185+
case bad
1186+
}
1187+
1188+
func sr10301(_ foo: SR10301<String,(Int,Error)>) {
1189+
switch foo {
1190+
case .value: return
1191+
case .error((_, SR10301Error.bad)): return
1192+
case .error((_, let err)):
1193+
_ = err
1194+
return
1195+
}
1196+
}
1197+
1198+
func sr10301_is(_ foo: SR10301<String,(Int,Error)>) {
1199+
switch foo {
1200+
case .value: return
1201+
case .error((_, is SR10301Error)): return
1202+
case .error((_, let err)):
1203+
_ = err
1204+
return
1205+
}
1206+
}
1207+
1208+
func sr10301_as(_ foo: SR10301<String,(Int,Error)>) {
1209+
switch foo {
1210+
case .value: return
1211+
case .error((_, let err as SR10301Error)):
1212+
_ = err
1213+
return
1214+
case .error((_, let err)):
1215+
_ = err
1216+
return
1217+
}
1218+
}

test/Sema/exhaustive_switch.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,3 +1135,43 @@ extension Result where T == NoError {
11351135
}
11361136
}
11371137
}
1138+
1139+
enum SR10301<T,E> {
1140+
case value(T)
1141+
case error(E)
1142+
}
1143+
enum SR10301Error: Error {
1144+
case bad
1145+
}
1146+
1147+
func sr10301(_ foo: SR10301<String,(Int,Error)>) {
1148+
switch foo {
1149+
case .value: return
1150+
case .error((_, SR10301Error.bad)): return
1151+
case .error((_, let err)):
1152+
_ = err
1153+
return
1154+
}
1155+
}
1156+
1157+
func sr10301_is(_ foo: SR10301<String,(Int,Error)>) {
1158+
switch foo {
1159+
case .value: return
1160+
case .error((_, is SR10301Error)): return
1161+
case .error((_, let err)):
1162+
_ = err
1163+
return
1164+
}
1165+
}
1166+
1167+
func sr10301_as(_ foo: SR10301<String,(Int,Error)>) {
1168+
switch foo {
1169+
case .value: return
1170+
case .error((_, let err as SR10301Error)):
1171+
_ = err
1172+
return
1173+
case .error((_, let err)):
1174+
_ = err
1175+
return
1176+
}
1177+
}

0 commit comments

Comments
 (0)