Skip to content

Commit a000b78

Browse files
committed
AST: Introduce ParamPackMatcher, for structural matching of function types
1 parent 9d16b82 commit a000b78

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

include/swift/AST/PackExpansionMatcher.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,29 @@ class TuplePackMatcher {
6262
bool match();
6363
};
6464

65+
/// Performs a structural match of two lists of (unlabeled) function
66+
/// parameters.
67+
///
68+
/// The invariant is that each list must only contain at most one pack
69+
/// expansion type. After collecting a common prefix and suffix, the
70+
/// pack expansion on either side asborbs the remaining elements on the
71+
/// other side.
72+
class ParamPackMatcher {
73+
ArrayRef<AnyFunctionType::Param> lhsParams;
74+
ArrayRef<AnyFunctionType::Param> rhsParams;
75+
76+
ASTContext &ctx;
77+
78+
public:
79+
SmallVector<MatchedPair, 4> pairs;
80+
81+
ParamPackMatcher(ArrayRef<AnyFunctionType::Param> lhsParams,
82+
ArrayRef<AnyFunctionType::Param> rhsParams,
83+
ASTContext &ctx);
84+
85+
bool match();
86+
};
87+
6588
} // end namespace swift
6689

6790
#endif // SWIFT_AST_TYPE_MATCHER_H

lib/AST/PackExpansionMatcher.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/Type.h"
2121
#include "swift/AST/Types.h"
2222
#include "llvm/ADT/SmallVector.h"
23+
#include <algorithm>
2324

2425
using namespace swift;
2526

@@ -104,4 +105,105 @@ bool TuplePackMatcher::match() {
104105
}
105106

106107
return false;
108+
}
109+
110+
ParamPackMatcher::ParamPackMatcher(
111+
ArrayRef<AnyFunctionType::Param> lhsParams,
112+
ArrayRef<AnyFunctionType::Param> rhsParams,
113+
ASTContext &ctx)
114+
: lhsParams(lhsParams), rhsParams(rhsParams), ctx(ctx) {}
115+
116+
bool ParamPackMatcher::match() {
117+
unsigned minLength = std::min(lhsParams.size(), rhsParams.size());
118+
119+
// Consume the longest possible prefix where neither type in
120+
// the pair is a pack expansion type.
121+
unsigned prefixLength = 0;
122+
for (unsigned i = 0; i < minLength; ++i) {
123+
auto lhsParam = lhsParams[i];
124+
auto rhsParam = rhsParams[i];
125+
126+
// FIXME: Check flags
127+
128+
auto lhsType = lhsParam.getPlainType();
129+
auto rhsType = rhsParam.getPlainType();
130+
131+
if (lhsType->is<PackExpansionType>() ||
132+
rhsType->is<PackExpansionType>()) {
133+
break;
134+
}
135+
136+
// FIXME: Check flags
137+
138+
pairs.emplace_back(lhsType, rhsType, i);
139+
++prefixLength;
140+
}
141+
142+
// Consume the longest possible suffix where neither type in
143+
// the pair is a pack expansion type.
144+
unsigned suffixLength = 0;
145+
for (unsigned i = 0; i < minLength - prefixLength; ++i) {
146+
auto lhsParam = lhsParams[lhsParams.size() - i - 1];
147+
auto rhsParam = rhsParams[rhsParams.size() - i - 1];
148+
149+
// FIXME: Check flags
150+
151+
auto lhsType = lhsParam.getPlainType();
152+
auto rhsType = rhsParam.getPlainType();
153+
154+
if (lhsType->is<PackExpansionType>() ||
155+
rhsType->is<PackExpansionType>()) {
156+
break;
157+
}
158+
159+
pairs.emplace_back(lhsType, rhsType, i);
160+
++suffixLength;
161+
}
162+
163+
assert(prefixLength + suffixLength <= lhsParams.size());
164+
assert(prefixLength + suffixLength <= rhsParams.size());
165+
166+
// Drop the consumed prefix and suffix from each list of types.
167+
lhsParams = lhsParams.drop_front(prefixLength).drop_back(suffixLength);
168+
rhsParams = rhsParams.drop_front(prefixLength).drop_back(suffixLength);
169+
170+
// If the left hand side is a single pack expansion type, bind it
171+
// to what remains of the right hand side.
172+
if (lhsParams.size() == 1 &&
173+
lhsParams[0].getPlainType()->is<PackExpansionType>()) {
174+
SmallVector<Type, 2> rhsTypes;
175+
for (auto rhsParam : rhsParams) {
176+
// FIXME: Check rhs flags
177+
rhsTypes.push_back(rhsParam.getPlainType());
178+
}
179+
auto rhs = PackType::get(ctx, rhsTypes);
180+
181+
// FIXME: Check lhs flags
182+
pairs.emplace_back(lhsParams[0].getPlainType(), rhs, prefixLength);
183+
return false;
184+
}
185+
186+
// If the right hand side is a single pack expansion type, bind it
187+
// to what remains of the left hand side.
188+
if (rhsParams.size() == 1 &&
189+
rhsParams[0].getPlainType()->is<PackExpansionType>()) {
190+
SmallVector<Type, 2> lhsTypes;
191+
for (auto lhsParam : lhsParams) {
192+
// FIXME: Check lhs flags
193+
lhsTypes.push_back(lhsParam.getPlainType());
194+
}
195+
auto lhs = PackType::get(ctx, lhsTypes);
196+
197+
// FIXME: Check rhs flags
198+
pairs.emplace_back(lhs, rhsParams[0].getPlainType(), prefixLength);
199+
return false;
200+
}
201+
202+
// Otherwise, all remaining possibilities are invalid:
203+
// - Neither side has any pack expansions, and they have different lengths.
204+
// - One side has a pack expansion but the other side is too short, eg
205+
// {Int, T..., Float} vs {Int}.
206+
// - The prefix and suffix are mismatched, so we're left with something
207+
// like {T..., Int} vs {Float, U...}.
208+
return true;
107209
}

0 commit comments

Comments
 (0)