Skip to content

Commit 7ae2d94

Browse files
committed
Short circuit subspace check with empty subjects
When determining whether one constructor pattern is a subspace of another, we only checked if the right-hand subspace was larger than the left. If the left is larger than the right then we can short-circuit the comparison once more because it cannot be a subspace. This also takes care of refutable casts in patterns tripping the duplicate case warning.
1 parent 0a0ab12 commit 7ae2d94

File tree

2 files changed

+38
-0
lines changed

2 files changed

+38
-0
lines changed

lib/Sema/TypeCheckSwitchStmt.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,10 +251,25 @@ namespace {
251251

252252
// Special Case: A constructor pattern may include the head but not
253253
// the payload patterns. In that case the space is covered.
254+
// This also acts to short-circuit comparisons with payload-less
255+
// constructors.
254256
if (other.getSpaces().empty()) {
255257
return true;
256258
}
257259

260+
// If 'this' constructor pattern has no payload and the other space
261+
// does, then 'this' covers more of the space only if the other
262+
// constructor isn't the explicit form.
263+
//
264+
// .case <= .case(_, _, _, ...)
265+
if (this->getSpaces().empty()) {
266+
return std::accumulate(other.getSpaces().begin(),
267+
other.getSpaces().end(),
268+
true, [](bool acc, const Space sp){
269+
return acc && sp.getKind() == SpaceKind::Type;
270+
});
271+
}
272+
258273
// H(a1, ..., an) <= H(b1, ..., bn) iff a1 <= b1 && ... && an <= bn
259274
auto i = this->getSpaces().begin();
260275
auto j = other.getSpaces().begin();

test/Sema/exhaustive_switch.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %target-typecheck-verify-swift
2+
23
func foo(a: Int?, b: Int?) -> Int {
34
switch (a, b) {
45
case (.none, _): return 1
@@ -286,3 +287,25 @@ func switcheroo(a: XX, b: XX) -> Int {
286287
return 13
287288
}
288289
}
290+
291+
enum PatternCasts {
292+
case one(Any)
293+
case two
294+
}
295+
296+
func checkPatternCasts() {
297+
// Pattern casts with this structure shouldn't warn about duplicate cases.
298+
let x: PatternCasts = .one("One")
299+
switch x {
300+
case .one(let s as String): print(s)
301+
case .one: break
302+
case .two: break
303+
}
304+
305+
// But should warn here.
306+
switch x {
307+
case .one(_): print(s)
308+
case .one: break // expected-warning {{case is already handled by previous patterns; consider removing it}}
309+
case .two: break
310+
}
311+
}

0 commit comments

Comments
 (0)