mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[CSSimplify] NFC: Refactor TupleMatcher to consolidate pack expansion matching
This commit is contained in:
@@ -2062,13 +2062,19 @@ class TupleMatcher {
|
||||
TupleType *tuple2;
|
||||
|
||||
public:
|
||||
enum class MatchKind : uint8_t {
|
||||
Equality,
|
||||
Subtype,
|
||||
Conversion,
|
||||
};
|
||||
|
||||
SmallVector<MatchedPair, 4> pairs;
|
||||
bool hasLabelMismatch = false;
|
||||
|
||||
TupleMatcher(TupleType *tuple1, TupleType *tuple2)
|
||||
: tuple1(tuple1), tuple2(tuple2) {}
|
||||
: tuple1(tuple1), tuple2(tuple2) {}
|
||||
|
||||
bool matchBind() {
|
||||
bool match(MatchKind kind, ConstraintLocatorBuilder locator) {
|
||||
// FIXME: TuplePackMatcher should completely replace the non-variadic
|
||||
// case too eventually.
|
||||
if (tuple1->containsPackExpansionType() ||
|
||||
@@ -2084,42 +2090,32 @@ public:
|
||||
if (tuple1->getNumElements() != tuple2->getNumElements())
|
||||
return true;
|
||||
|
||||
for (unsigned i = 0, n = tuple1->getNumElements(); i != n; ++i) {
|
||||
const auto &elt1 = tuple1->getElement(i);
|
||||
const auto &elt2 = tuple2->getElement(i);
|
||||
switch (kind) {
|
||||
case MatchKind::Equality:
|
||||
return matchEquality(isInPatternMatchingContext(locator));
|
||||
|
||||
// If the names don't match, we have a conflict.
|
||||
if (elt1.getName() != elt2.getName())
|
||||
return true;
|
||||
case MatchKind::Subtype:
|
||||
return matchSubtype();
|
||||
|
||||
pairs.emplace_back(elt1.getType(), elt2.getType(), i, i);
|
||||
case MatchKind::Conversion:
|
||||
return matchConversion();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool matchInPatternMatchingContext() {
|
||||
// FIXME: TuplePackMatcher should completely replace the non-variadic
|
||||
// case too eventually.
|
||||
if (tuple1->containsPackExpansionType() ||
|
||||
tuple2->containsPackExpansionType()) {
|
||||
TuplePackMatcher matcher(tuple1, tuple2);
|
||||
if (matcher.match())
|
||||
return true;
|
||||
|
||||
pairs = matcher.pairs;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tuple1->getNumElements() != tuple2->getNumElements())
|
||||
return true;
|
||||
|
||||
private:
|
||||
bool matchEquality(bool inPatternMatchingContext) {
|
||||
for (unsigned i = 0, n = tuple1->getNumElements(); i != n; ++i) {
|
||||
const auto &elt1 = tuple1->getElement(i);
|
||||
const auto &elt2 = tuple2->getElement(i);
|
||||
|
||||
if (elt1.hasName() && elt1.getName() != elt2.getName())
|
||||
return true;
|
||||
if (inPatternMatchingContext) {
|
||||
if (elt1.hasName() && elt1.getName() != elt2.getName())
|
||||
return true;
|
||||
} else {
|
||||
// If the names don't match, we have a conflict.
|
||||
if (elt1.getName() != elt2.getName())
|
||||
return true;
|
||||
}
|
||||
|
||||
pairs.emplace_back(elt1.getType(), elt2.getType(), i, i);
|
||||
}
|
||||
@@ -2128,21 +2124,6 @@ public:
|
||||
}
|
||||
|
||||
bool matchSubtype() {
|
||||
// FIXME: TuplePackMatcher should completely replace the non-variadic
|
||||
// case too eventually.
|
||||
if (tuple1->containsPackExpansionType() ||
|
||||
tuple2->containsPackExpansionType()) {
|
||||
TuplePackMatcher matcher(tuple1, tuple2);
|
||||
if (matcher.match())
|
||||
return true;
|
||||
|
||||
pairs = matcher.pairs;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tuple1->getNumElements() != tuple2->getNumElements())
|
||||
return true;
|
||||
|
||||
for (unsigned i = 0, n = tuple1->getNumElements(); i != n; ++i) {
|
||||
const auto &elt1 = tuple1->getElement(i);
|
||||
const auto &elt2 = tuple2->getElement(i);
|
||||
@@ -2166,18 +2147,6 @@ public:
|
||||
}
|
||||
|
||||
bool matchConversion() {
|
||||
// FIXME: TuplePackMatcher should completely replace the non-variadic
|
||||
// case too eventually.
|
||||
if (tuple1->containsPackExpansionType() ||
|
||||
tuple2->containsPackExpansionType()) {
|
||||
TuplePackMatcher matcher(tuple1, tuple2);
|
||||
if (matcher.match())
|
||||
return true;
|
||||
|
||||
pairs = matcher.pairs;
|
||||
return false;
|
||||
}
|
||||
|
||||
SmallVector<unsigned, 4> sources;
|
||||
if (computeTupleShuffle(tuple1, tuple2, sources))
|
||||
return true;
|
||||
@@ -2201,23 +2170,16 @@ ConstraintSystem::TypeMatchResult
|
||||
ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
|
||||
ConstraintKind kind, TypeMatchOptions flags,
|
||||
ConstraintLocatorBuilder locator) {
|
||||
TupleMatcher matcher(tuple1, tuple2);
|
||||
using TupleMatchKind = TupleMatcher::MatchKind;
|
||||
|
||||
ConstraintKind subkind;
|
||||
TupleMatchKind matchKind;
|
||||
|
||||
switch (kind) {
|
||||
case ConstraintKind::Bind:
|
||||
case ConstraintKind::Equal: {
|
||||
subkind = kind;
|
||||
|
||||
if (isInPatternMatchingContext(locator)) {
|
||||
if (matcher.matchInPatternMatchingContext())
|
||||
return getTypeMatchFailure(locator);
|
||||
} else {
|
||||
if (matcher.matchBind())
|
||||
return getTypeMatchFailure(locator);
|
||||
}
|
||||
|
||||
matchKind = TupleMatchKind::Equality;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2227,17 +2189,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
|
||||
case ConstraintKind::Subtype:
|
||||
case ConstraintKind::BindToPointerType: {
|
||||
subkind = kind;
|
||||
|
||||
if (matcher.matchSubtype())
|
||||
return getTypeMatchFailure(locator);
|
||||
|
||||
if (matcher.hasLabelMismatch) {
|
||||
// If we had a label mismatch, emit a warning. This is something we
|
||||
// shouldn't permit, as it's more permissive than what a conversion would
|
||||
// allow. Ideally we'd turn this into an error in Swift 6 mode.
|
||||
recordFix(AllowTupleLabelMismatch::create(
|
||||
*this, tuple1, tuple2, getConstraintLocator(locator)));
|
||||
}
|
||||
matchKind = TupleMatchKind::Subtype;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2245,11 +2197,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
|
||||
case ConstraintKind::ArgumentConversion:
|
||||
case ConstraintKind::OperatorArgumentConversion: {
|
||||
subkind = ConstraintKind::Conversion;
|
||||
|
||||
// Compute the element shuffles for conversions.
|
||||
if (matcher.matchConversion())
|
||||
return getTypeMatchFailure(locator);
|
||||
|
||||
matchKind = TupleMatchKind::Conversion;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2289,6 +2237,19 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
|
||||
llvm_unreachable("Bad constraint kind in matchTupleTypes()");
|
||||
}
|
||||
|
||||
TupleMatcher matcher(tuple1, tuple2);
|
||||
|
||||
if (matcher.match(matchKind, locator))
|
||||
return getTypeMatchFailure(locator);
|
||||
|
||||
if (matcher.hasLabelMismatch) {
|
||||
// If we had a label mismatch, emit a warning. This is something we
|
||||
// shouldn't permit, as it's more permissive than what a conversion would
|
||||
// allow. Ideally we'd turn this into an error in Swift 6 mode.
|
||||
recordFix(AllowTupleLabelMismatch::create(*this, tuple1, tuple2,
|
||||
getConstraintLocator(locator)));
|
||||
}
|
||||
|
||||
TypeMatchOptions subflags = getDefaultDecompositionOptions(flags);
|
||||
|
||||
for (auto pair : matcher.pairs) {
|
||||
|
||||
Reference in New Issue
Block a user