Skip to content

Commit 9d16b82

Browse files
committed
AST: Move Sema's TuplePackMatcher to AST
I'm also going to use it in TypeMatcher, for the Requirement Machine's same-type requirement desugaring.
1 parent bbaee23 commit 9d16b82

File tree

4 files changed

+184
-102
lines changed

4 files changed

+184
-102
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//===--- PackExpansionMatcher.h - Matching pack expansions ------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Utilities for structural matching of sequences of types containing pack
14+
// expansions.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_AST_PACK_EXPANSION_MATCHER_H
19+
#define SWIFT_AST_PACK_EXPANSION_MATCHER_H
20+
21+
#include "swift/AST/Type.h"
22+
#include "swift/AST/Types.h"
23+
#include "llvm/ADT/ArrayRef.h"
24+
#include "llvm/ADT/SmallVector.h"
25+
26+
namespace swift {
27+
28+
class ASTContext;
29+
30+
/// The result of a match. If one of lhs or rhs is a pack expansion type,
31+
/// the other one is a pack type.
32+
struct MatchedPair {
33+
Type lhs;
34+
Type rhs;
35+
36+
// An index into the original left-hand side.
37+
unsigned idx;
38+
39+
MatchedPair(Type lhs, Type rhs, unsigned idx)
40+
: lhs(lhs), rhs(rhs), idx(idx) {}
41+
};
42+
43+
/// Performs a structural match of two lists of tuple elements. The invariant
44+
/// is that a pack expansion type must not be followed by an unlabeled
45+
/// element, that is, it is either the last element or the next element has
46+
/// a label.
47+
///
48+
/// In this manner, an element with a pack expansion type "absorbs" all
49+
/// unlabeled elements up to the next label. An element with any other type
50+
/// matches exactly one element on the other side.
51+
class TuplePackMatcher {
52+
ArrayRef<TupleTypeElt> lhsElts;
53+
ArrayRef<TupleTypeElt> rhsElts;
54+
55+
ASTContext &ctx;
56+
57+
public:
58+
SmallVector<MatchedPair, 4> pairs;
59+
60+
TuplePackMatcher(TupleType *lhsTuple, TupleType *rhsTuple);
61+
62+
bool match();
63+
};
64+
65+
} // end namespace swift
66+
67+
#endif // SWIFT_AST_TYPE_MATCHER_H

lib/AST/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ add_swift_host_library(swiftAST STATIC
7171
NameLookupRequests.cpp
7272
OperatorNameLookup.cpp
7373
PackConformance.cpp
74+
PackExpansionMatcher.cpp
7475
Parameter.cpp
7576
Pattern.cpp
7677
PlatformKind.cpp

lib/AST/PackExpansionMatcher.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//===--- PackExpansionMatcher.cpp - Matching pack expansions --------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Utilities for structural matching of sequences of types containing pack
14+
// expansions.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#include "swift/AST/PackExpansionMatcher.h"
19+
#include "swift/AST/ASTContext.h"
20+
#include "swift/AST/Type.h"
21+
#include "swift/AST/Types.h"
22+
#include "llvm/ADT/SmallVector.h"
23+
24+
using namespace swift;
25+
26+
static PackType *gatherTupleElements(ArrayRef<TupleTypeElt> &elts,
27+
Identifier name,
28+
ASTContext &ctx) {
29+
SmallVector<Type, 2> types;
30+
31+
if (!elts.empty() && elts.front().getName() == name) {
32+
do {
33+
types.push_back(elts.front().getType());
34+
elts = elts.slice(1);
35+
} while (!elts.empty() && !elts.front().hasName());
36+
}
37+
38+
return PackType::get(ctx, types);
39+
}
40+
41+
TuplePackMatcher::TuplePackMatcher(TupleType *lhsTuple, TupleType *rhsTuple)
42+
: lhsElts(lhsTuple->getElements()),
43+
rhsElts(rhsTuple->getElements()),
44+
ctx(lhsTuple->getASTContext()) {}
45+
46+
bool TuplePackMatcher::match() {
47+
unsigned idx = 0;
48+
49+
// Iterate over the two tuples in parallel, popping elements from
50+
// the start.
51+
while (true) {
52+
// If both tuples have been exhausted, we're done.
53+
if (lhsElts.empty() && rhsElts.empty())
54+
return false;
55+
56+
if (lhsElts.empty()) {
57+
assert(!rhsElts.empty());
58+
return true;
59+
}
60+
61+
// A pack expansion type on the left hand side absorbs all elements
62+
// from the right hand side up to the next mismatched label.
63+
auto lhsElt = lhsElts.front();
64+
if (lhsElt.getType()->is<PackExpansionType>()) {
65+
lhsElts = lhsElts.slice(1);
66+
67+
assert(lhsElts.empty() || lhsElts.front().hasName() &&
68+
"Tuple element with pack expansion type cannot be followed "
69+
"by an unlabeled element");
70+
71+
auto *rhs = gatherTupleElements(rhsElts, lhsElt.getName(), ctx);
72+
pairs.emplace_back(lhsElt.getType(), rhs, idx++);
73+
continue;
74+
}
75+
76+
if (rhsElts.empty()) {
77+
assert(!lhsElts.empty());
78+
return true;
79+
}
80+
81+
// A pack expansion type on the right hand side absorbs all elements
82+
// from the left hand side up to the next mismatched label.
83+
auto rhsElt = rhsElts.front();
84+
if (rhsElt.getType()->is<PackExpansionType>()) {
85+
rhsElts = rhsElts.slice(1);
86+
87+
assert(rhsElts.empty() || rhsElts.front().hasName() &&
88+
"Tuple element with pack expansion type cannot be followed "
89+
"by an unlabeled element");
90+
91+
auto *lhs = gatherTupleElements(lhsElts, rhsElt.getName(), ctx);
92+
pairs.emplace_back(lhs, rhsElt.getType(), idx++);
93+
continue;
94+
}
95+
96+
// Neither side is a pack expansion. We must have an exact match.
97+
if (lhsElt.getName() != rhsElt.getName())
98+
return true;
99+
100+
lhsElts = lhsElts.slice(1);
101+
rhsElts = rhsElts.slice(1);
102+
103+
pairs.emplace_back(lhsElt.getType(), rhsElt.getType(), idx++);
104+
}
105+
106+
return false;
107+
}

lib/Sema/CSSimplify.cpp

Lines changed: 9 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/AST/GenericSignature.h"
2525
#include "swift/AST/Initializer.h"
2626
#include "swift/AST/NameLookupRequests.h"
27+
#include "swift/AST/PackExpansionMatcher.h"
2728
#include "swift/AST/ParameterList.h"
2829
#include "swift/AST/PropertyWrappers.h"
2930
#include "swift/AST/ProtocolConformance.h"
@@ -2160,108 +2161,6 @@ static bool isInPatternMatchingContext(ConstraintLocatorBuilder locator) {
21602161

21612162
namespace {
21622163

2163-
struct MatchedPair {
2164-
Type lhs;
2165-
Type rhs;
2166-
unsigned idx;
2167-
2168-
MatchedPair(Type lhs, Type rhs, unsigned idx)
2169-
: lhs(lhs), rhs(rhs), idx(idx) {}
2170-
};
2171-
2172-
static PackType *gatherTupleElements(ArrayRef<TupleTypeElt> &elts,
2173-
Identifier name,
2174-
ASTContext &ctx) {
2175-
SmallVector<Type, 2> types;
2176-
2177-
if (!elts.empty() && elts.front().getName() == name) {
2178-
do {
2179-
types.push_back(elts.front().getType());
2180-
elts = elts.slice(1);
2181-
} while (!elts.empty() && !elts.front().hasName());
2182-
}
2183-
2184-
return PackType::get(ctx, types);
2185-
}
2186-
2187-
class TuplePackMatcher {
2188-
ASTContext &ctx;
2189-
2190-
ArrayRef<TupleTypeElt> lhsElts;
2191-
ArrayRef<TupleTypeElt> rhsElts;
2192-
2193-
public:
2194-
SmallVector<MatchedPair, 4> pairs;
2195-
2196-
TuplePackMatcher(TupleType *lhsTuple, TupleType *rhsTuple)
2197-
: ctx(lhsTuple->getASTContext()),
2198-
lhsElts(lhsTuple->getElements()),
2199-
rhsElts(rhsTuple->getElements()) {}
2200-
2201-
bool match() {
2202-
unsigned idx = 0;
2203-
2204-
// Iterate over the two tuples in parallel, popping elements from
2205-
// the start.
2206-
while (true) {
2207-
// If both tuples have been exhausted, we're done.
2208-
if (lhsElts.empty() && rhsElts.empty())
2209-
return false;
2210-
2211-
if (lhsElts.empty()) {
2212-
assert(!rhsElts.empty());
2213-
return true;
2214-
}
2215-
2216-
// A pack expansion type on the left hand side absorbs all elements
2217-
// from the right hand side up to the next mismatched label.
2218-
auto lhsElt = lhsElts.front();
2219-
if (lhsElt.getType()->is<PackExpansionType>()) {
2220-
lhsElts = lhsElts.slice(1);
2221-
2222-
assert(lhsElts.empty() || lhsElts.front().hasName() &&
2223-
"Tuple element with pack expansion type cannot be followed "
2224-
"by an unlabeled element");
2225-
2226-
auto *rhs = gatherTupleElements(rhsElts, lhsElt.getName(), ctx);
2227-
pairs.emplace_back(lhsElt.getType(), rhs, idx++);
2228-
continue;
2229-
}
2230-
2231-
if (rhsElts.empty()) {
2232-
assert(!lhsElts.empty());
2233-
return true;
2234-
}
2235-
2236-
// A pack expansion type on the right hand side absorbs all elements
2237-
// from the left hand side up to the next mismatched label.
2238-
auto rhsElt = rhsElts.front();
2239-
if (rhsElt.getType()->is<PackExpansionType>()) {
2240-
rhsElts = rhsElts.slice(1);
2241-
2242-
assert(rhsElts.empty() || rhsElts.front().hasName() &&
2243-
"Tuple element with pack expansion type cannot be followed "
2244-
"by an unlabeled element");
2245-
2246-
auto *lhs = gatherTupleElements(lhsElts, rhsElt.getName(), ctx);
2247-
pairs.emplace_back(lhs, rhsElt.getType(), idx++);
2248-
continue;
2249-
}
2250-
2251-
// Neither side is a pack expansion. We must have an exact match.
2252-
if (lhsElt.getName() != rhsElt.getName())
2253-
return true;
2254-
2255-
lhsElts = lhsElts.slice(1);
2256-
rhsElts = rhsElts.slice(1);
2257-
2258-
pairs.emplace_back(lhsElt.getType(), rhsElt.getType(), idx++);
2259-
}
2260-
2261-
return false;
2262-
}
2263-
};
2264-
22652164
class TupleMatcher {
22662165
TupleType *tuple1;
22672166
TupleType *tuple2;
@@ -2274,6 +2173,8 @@ class TupleMatcher {
22742173
: tuple1(tuple1), tuple2(tuple2) {}
22752174

22762175
bool matchBind() {
2176+
// FIXME: TuplePackMatcher should completely replace the non-variadic
2177+
// case too eventually.
22772178
if (tuple1->containsPackExpansionType() ||
22782179
tuple2->containsPackExpansionType()) {
22792180
TuplePackMatcher matcher(tuple1, tuple2);
@@ -2302,6 +2203,8 @@ class TupleMatcher {
23022203
}
23032204

23042205
bool matchInPatternMatchingContext() {
2206+
// FIXME: TuplePackMatcher should completely replace the non-variadic
2207+
// case too eventually.
23052208
if (tuple1->containsPackExpansionType() ||
23062209
tuple2->containsPackExpansionType()) {
23072210
TuplePackMatcher matcher(tuple1, tuple2);
@@ -2329,6 +2232,8 @@ class TupleMatcher {
23292232
}
23302233

23312234
bool matchSubtype() {
2235+
// FIXME: TuplePackMatcher should completely replace the non-variadic
2236+
// case too eventually.
23322237
if (tuple1->containsPackExpansionType() ||
23332238
tuple2->containsPackExpansionType()) {
23342239
TuplePackMatcher matcher(tuple1, tuple2);
@@ -2365,6 +2270,8 @@ class TupleMatcher {
23652270
}
23662271

23672272
bool matchConversion() {
2273+
// FIXME: TuplePackMatcher should completely replace the non-variadic
2274+
// case too eventually.
23682275
if (tuple1->containsPackExpansionType() ||
23692276
tuple2->containsPackExpansionType()) {
23702277
TuplePackMatcher matcher(tuple1, tuple2);

0 commit comments

Comments
 (0)