Skip to content

Commit 1f222f3

Browse files
committed
[ConstraintSystem] Make sure pattern matching tuple destructuring works both ways
Consider following example: ```swift enum E { case foo((x: Int, y: Int)) case bar(x: Int, y: Int) } func test(e: E) { if case .foo(let x, let y) = e {} if case .bar(let tuple) = e {} } ``` Both of `if case` expressions have to be supported: 1. `case .foo(let x, let y) = e` allows a single tuple parameter to be "destructured" into multiple arguments. 2. `case .bar(let tuple) = e` allows to match multiple parameters with a single tuple argument. Resolves: rdar://problem/60061646
1 parent 8b6f66b commit 1f222f3

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

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)