Skip to content

Commit 6a5069d

Browse files
authored
Merge pull request swiftlang#30245 from xedin/rdar-60061646
[ConstraintSystem] Make sure pattern matching tuple destructuring works both ways
2 parents 4dad6c5 + 1f222f3 commit 6a5069d

File tree

2 files changed

+51
-5
lines changed

2 files changed

+51
-5
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,10 +1684,33 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
16841684
}
16851685
} else if (last->getKind() == ConstraintLocator::PatternMatch &&
16861686
isa<EnumElementPattern>(
1687-
last->castTo<LocatorPathElt::PatternMatch>().getPattern()) &&
1688-
isSingleTupleParam(ctx, func1Params) &&
1689-
canImplodeParams(func2Params)) {
1690-
implodeParams(func2Params);
1687+
last->castTo<LocatorPathElt::PatternMatch>().getPattern())) {
1688+
// Consider following example:
1689+
//
1690+
// enum E {
1691+
// case foo((x: Int, y: Int))
1692+
// case bar(x: Int, y: Int)
1693+
// }
1694+
//
1695+
// func test(e: E) {
1696+
// if case .foo(let x, let y) = e {}
1697+
// if case .bar(let tuple) = e {}
1698+
// }
1699+
//
1700+
// Both of `if case` expressions have to be supported:
1701+
//
1702+
// 1. `case .foo(let x, let y) = e` allows a single tuple
1703+
// parameter to be "destructured" into multiple arguments.
1704+
//
1705+
// 2. `case .bar(let tuple) = e` allows to match multiple
1706+
// parameters with a single tuple argument.
1707+
if (isSingleTupleParam(ctx, func1Params) &&
1708+
canImplodeParams(func2Params)) {
1709+
implodeParams(func2Params);
1710+
} else if (isSingleTupleParam(ctx, func2Params) &&
1711+
canImplodeParams(func1Params)) {
1712+
implodeParams(func1Params);
1713+
}
16911714
}
16921715
}
16931716

test/Constraints/patterns.swift

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ func rdar_60048356() {
443443
}
444444

445445
enum Failure {
446-
case closed(Info)
446+
case closed(Info) // expected-note {{'closed' declared here}}
447447
}
448448

449449
enum Reason {
@@ -454,4 +454,27 @@ func rdar_60048356() {
454454
if case .close(.closed((code: .normalClosure, _))) = reason { // Ok
455455
}
456456
}
457+
458+
// rdar://problem/60061646
459+
func test(e: Failure) {
460+
if case .closed(code: .normalClosure, _) = e { // Ok
461+
// expected-warning@-1 {{enum case 'closed' has one associated value that is a tuple of 2 elements}}
462+
}
463+
}
464+
465+
enum E {
466+
case foo((x: Int, y: Int)) // expected-note {{declared here}}
467+
case bar(x: Int, y: Int) // expected-note {{declared here}}
468+
}
469+
470+
func test_destructing(e: E) {
471+
if case .foo(let x, let y) = e { // Ok (destructring)
472+
// expected-warning@-1 {{enum case 'foo' has one associated value that is a tuple of 2 elements}}
473+
_ = x == y
474+
}
475+
if case .bar(let tuple) = e { // Ok (matching via tuple)
476+
// expected-warning@-1 {{enum case 'bar' has 2 associated values; matching them as a tuple is deprecated}}
477+
_ = tuple.0 == tuple.1
478+
}
479+
}
457480
}

0 commit comments

Comments
 (0)