Skip to content

Commit 8b6f66b

Browse files
authored
Merge pull request swiftlang#30223 from xedin/rdar-60048356
[ConstraintSystem] Preserve label matching rules in pattern matching …
2 parents 8ce5c77 + 87878a6 commit 8b6f66b

File tree

2 files changed

+74
-14
lines changed

2 files changed

+74
-14
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,20 +1141,51 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
11411141
if (tuple1->getNumElements() != tuple2->getNumElements())
11421142
return getTypeMatchFailure(locator);
11431143

1144+
// Determine whether this conversion is performed as part
1145+
// of a larger pattern matching operation.
1146+
bool inPatternMatchingContext = false;
1147+
{
1148+
SmallVector<LocatorPathElt, 4> path;
1149+
(void)locator.getLocatorParts(path);
1150+
1151+
if (!path.empty()) {
1152+
// Direct pattern matching between tuple pattern and tuple type.
1153+
if (path.back().is<LocatorPathElt::PatternMatch>()) {
1154+
inPatternMatchingContext = true;
1155+
} else if (path.size() > 1) {
1156+
// sub-pattern matching as part of the enum element matching
1157+
// where sub-element is a tuple pattern e.g.
1158+
// `case .foo((a: 42, _)) = question`
1159+
auto lastIdx = path.size() - 1;
1160+
if (path[lastIdx - 1].is<LocatorPathElt::PatternMatch>() &&
1161+
path[lastIdx].is<LocatorPathElt::FunctionArgument>())
1162+
inPatternMatchingContext = true;
1163+
}
1164+
}
1165+
}
1166+
11441167
for (unsigned i = 0, n = tuple1->getNumElements(); i != n; ++i) {
11451168
const auto &elt1 = tuple1->getElement(i);
11461169
const auto &elt2 = tuple2->getElement(i);
11471170

1148-
// If the names don't match, we may have a conflict.
1149-
if (elt1.getName() != elt2.getName()) {
1150-
// Same-type requirements require exact name matches.
1151-
if (kind <= ConstraintKind::Equal)
1171+
// If the tuple pattern had a label for the tuple element,
1172+
// it must match the label for the tuple type being matched.
1173+
if (inPatternMatchingContext) {
1174+
if (elt1.hasName() && elt1.getName() != elt2.getName()) {
11521175
return getTypeMatchFailure(locator);
1176+
}
1177+
} else {
1178+
// If the names don't match, we may have a conflict.
1179+
if (elt1.getName() != elt2.getName()) {
1180+
// Same-type requirements require exact name matches.
1181+
if (kind <= ConstraintKind::Equal)
1182+
return getTypeMatchFailure(locator);
11531183

1154-
// For subtyping constraints, just make sure that this name isn't
1155-
// used at some other position.
1156-
if (elt2.hasName() && tuple1->getNamedElementId(elt2.getName()) != -1)
1157-
return getTypeMatchFailure(locator);
1184+
// For subtyping constraints, just make sure that this name isn't
1185+
// used at some other position.
1186+
if (elt2.hasName() && tuple1->getNamedElementId(elt2.getName()) != -1)
1187+
return getTypeMatchFailure(locator);
1188+
}
11581189
}
11591190

11601191
// Variadic bit must match.
@@ -1794,14 +1825,21 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
17941825
// FIXME: We should check value ownership too, but it's not completely
17951826
// trivial because of inout-to-pointer conversions.
17961827

1828+
// For equality contravariance doesn't matter, but let's make sure
1829+
// that types are matched in original order because that is important
1830+
// when function types are equated as part of pattern matching.
1831+
auto paramType1 = kind == ConstraintKind::Equal ? func1Param.getOldType()
1832+
: func2Param.getOldType();
1833+
1834+
auto paramType2 = kind == ConstraintKind::Equal ? func2Param.getOldType()
1835+
: func1Param.getOldType();
1836+
17971837
// Compare the parameter types.
1798-
auto result = matchTypes(func2Param.getOldType(),
1799-
func1Param.getOldType(),
1800-
subKind, subflags,
1838+
auto result = matchTypes(paramType1, paramType2, subKind, subflags,
18011839
(func1Params.size() == 1
1802-
? argumentLocator
1803-
: argumentLocator.withPathElement(
1804-
LocatorPathElt::TupleElement(i))));
1840+
? argumentLocator
1841+
: argumentLocator.withPathElement(
1842+
LocatorPathElt::TupleElement(i))));
18051843
if (result.isFailure())
18061844
return result;
18071845
}

test/Constraints/patterns.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,3 +433,25 @@ switch sr7799_1 {
433433

434434
if case .baz = sr7799_1 {} // Ok
435435
if case .bar? = sr7799_1 {} // Ok
436+
437+
// rdar://problem/60048356 - `if case` fails when `_` pattern doesn't have a label
438+
func rdar_60048356() {
439+
typealias Info = (code: ErrorCode, reason: String)
440+
441+
enum ErrorCode {
442+
case normalClosure
443+
}
444+
445+
enum Failure {
446+
case closed(Info)
447+
}
448+
449+
enum Reason {
450+
case close(Failure)
451+
}
452+
453+
func test(_ reason: Reason) {
454+
if case .close(.closed((code: .normalClosure, _))) = reason { // Ok
455+
}
456+
}
457+
}

0 commit comments

Comments
 (0)