@@ -167,207 +167,65 @@ ProtocolConformanceRef PackConformance::subst(SubstitutionMap subMap,
167
167
return subst (IFS);
168
168
}
169
169
170
- // TODO: Move this elsewhere since it's generally useful
171
- static bool arePackShapesEqual (PackType *lhs, PackType *rhs) {
172
- if (lhs->getNumElements () != rhs->getNumElements ())
173
- return false ;
174
-
175
- for (unsigned i = 0 , e = lhs->getNumElements (); i < e; ++i) {
176
- auto lhsElt = lhs->getElementType (i);
177
- auto rhsElt = rhs->getElementType (i);
178
-
179
- if (lhsElt->is <PackExpansionType>() != rhsElt->is <PackExpansionType>())
180
- return false ;
181
- }
182
-
183
- return true ;
184
- }
185
-
186
- static bool isRootParameterPack (Type t) {
187
- if (auto *paramTy = t->getAs <GenericTypeParamType>()) {
188
- return paramTy->isParameterPack ();
189
- } else if (auto *archetypeTy = t->getAs <PackArchetypeType>()) {
190
- return archetypeTy->isRoot ();
191
- }
192
-
193
- return false ;
194
- }
195
-
196
- static bool isRootedInParameterPack (Type t) {
197
- if (auto *archetypeTy = t->getAs <PackArchetypeType>()) {
198
- return true ;
199
- }
200
-
201
- return t->getRootGenericParam ()->isParameterPack ();
202
- }
203
-
204
170
namespace {
205
171
206
- template <typename ImplClass>
207
- class PackExpander {
208
- protected:
172
+ struct PackConformanceExpander {
209
173
InFlightSubstitution &IFS;
174
+ ArrayRef<ProtocolConformanceRef> origConformances;
210
175
211
- PackExpander (InFlightSubstitution &IFS) : IFS(IFS) {}
212
-
213
- ImplClass *asImpl () {
214
- return static_cast <ImplClass *>(this );
215
- }
216
-
217
- // / We're replacing a pack expansion type with a pack -- flatten the pack
218
- // / using the pack expansion's pattern.
219
- void addExpandedExpansion (Type origPatternType, PackType *expandedCountType,
220
- unsigned i) {
221
-
222
- // Get all pack parameters referenced from the pattern.
223
- SmallVector<Type, 2 > rootParameterPacks;
224
- origPatternType->getTypeParameterPacks (rootParameterPacks);
225
-
226
- // Each pack parameter referenced from the pattern must be replaced
227
- // with a pack type, and all pack types must have the same shape as
228
- // the expanded count pack type.
229
- llvm::SmallDenseMap<Type, PackType *, 2 > expandedPacks;
230
- for (auto origParamType : rootParameterPacks) {
231
- auto substParamType = origParamType.subst (IFS);
232
-
233
- if (auto expandedParamType = substParamType->template getAs <PackType>()) {
234
- assert (arePackShapesEqual (expandedParamType, expandedCountType) &&
235
- " TODO: Return an invalid conformance if this fails" );
236
-
237
- auto inserted = expandedPacks.insert (
238
- std::make_pair (origParamType->getCanonicalType (),
239
- expandedParamType)).second ;
240
- assert (inserted &&
241
- " getTypeParameterPacks() should not return duplicates" );
242
- } else {
243
- assert (false &&
244
- " TODO: Return an invalid conformance if this fails" );
245
- }
246
- }
247
-
248
- // For each element of the expanded count, compute the substituted
249
- // pattern type.
250
- for (unsigned j = 0 , ee = expandedCountType->getNumElements (); j < ee; ++j) {
251
- auto projectedSubs = [&](SubstitutableType *type) -> Type {
252
- // Nested sequence archetypes get passed in here, but we must
253
- // handle them via the standard nested type path.
254
- if (auto *archetypeType = dyn_cast<ArchetypeType>(type)) {
255
- if (!archetypeType->isRoot ())
256
- return Type ();
257
- }
258
-
259
- // Compute the substituted type using our parent substitutions.
260
- auto substType = Type (type).subst (IFS);
261
-
262
- // If the substituted type is a pack, project the jth element.
263
- if (isRootParameterPack (type)) {
264
- // FIXME: What if you have something like G<T...>... where G<> is
265
- // variadic?
266
- assert (substType->template is <PackType>() &&
267
- " TODO: Return an invalid conformance if this fails" );
268
- auto *packType = substType->template castTo <PackType>();
269
- assert (arePackShapesEqual (packType, expandedCountType) &&
270
- " TODO: Return an invalid conformance if this fails" );
271
-
272
- return packType->getElementType (j);
273
- }
274
-
275
- return IFS.substType (type);
276
- };
277
-
278
- auto projectedConformances = [&](CanType origType, Type substType,
279
- ProtocolDecl *proto) -> ProtocolConformanceRef {
280
- auto substConformance =
281
- IFS.lookupConformance (origType, substType, proto);
282
-
283
- // If the substituted conformance is a pack, project the jth element.
284
- if (isRootedInParameterPack (origType)) {
285
- return substConformance.getPack ()->getPatternConformances ()[j];
286
- }
287
-
288
- return substConformance;
289
- };
290
-
291
- auto origCountElement = expandedCountType->getElementType (j);
292
- auto substCountElement = origCountElement.subst (
293
- projectedSubs, projectedConformances, IFS.getOptions ());
294
-
295
- asImpl ()->add (origCountElement, substCountElement, i);
296
- }
297
- }
298
-
299
- // / A pack expansion remains unexpanded, so we substitute the pattern and
300
- // / form a new pack expansion.
301
- void addUnexpandedExpansion (Type origPatternType, Type substCountType,
302
- unsigned i) {
303
- auto substPatternType = origPatternType.subst (IFS);
304
- auto substExpansion = PackExpansionType::get (substPatternType, substCountType);
176
+ public:
177
+ // Results built up by the expansion.
178
+ SmallVector<Type, 4 > substElementTypes;
179
+ SmallVector<ProtocolConformanceRef, 4 > substConformances;
305
180
306
- asImpl ()->add (origPatternType, substExpansion, i);
307
- }
181
+ PackConformanceExpander (InFlightSubstitution &IFS,
182
+ ArrayRef<ProtocolConformanceRef> origConformances)
183
+ : IFS(IFS), origConformances(origConformances) {}
308
184
309
- // / Scalar elements of the original pack are substituted and added to the
310
- // / flattened pack.
311
- void addScalar (Type origElement, unsigned i) {
312
- auto substElement = origElement.subst (IFS);
185
+ private:
186
+ // / Substitute a scalar element of the original pack.
187
+ void substScalar (Type origElementType,
188
+ ProtocolConformanceRef origConformance) {
189
+ auto substElementType = origElementType.subst (IFS);
190
+ auto substConformance = origConformance.subst (origElementType, IFS);
313
191
314
- asImpl ()->add (origElement, substElement, i);
192
+ substElementTypes.push_back (substElementType);
193
+ substConformances.push_back (substConformance);
315
194
}
316
195
317
- // / Potentially expand an element of the original pack.
318
- void maybeExpandExpansion (PackExpansionType *origExpansion, unsigned i) {
319
- auto origPatternType = origExpansion-> getPatternType ();
320
- auto origCountType = origExpansion-> getCountType ();
321
-
322
- auto substCountType = origCountType. subst (IFS );
323
-
324
- // If the substituted count type is a pack, we're expanding the
325
- // original element.
326
- if ( auto *expandedCountType = substCountType-> template getAs <PackType>()) {
327
- addExpandedExpansion (origPatternType, expandedCountType, i );
328
- return ;
329
- }
330
-
331
- addUnexpandedExpansion (origPatternType, substCountType, i );
196
+ // / Substitute and expand an expansion element of the original pack.
197
+ void substExpansion (PackExpansionType *origExpansionType,
198
+ ProtocolConformanceRef origConformance) {
199
+ IFS. expandPackExpansionType (origExpansionType,
200
+ [&](Type substComponentType) {
201
+ auto origPatternType = origExpansionType-> getPatternType ( );
202
+
203
+ // Just substitute the conformance. We don't directly represent
204
+ // pack expansion conformances here; it's sort of implicit in the
205
+ // corresponding pack element type.
206
+ auto substConformance = origConformance. subst (origPatternType, IFS );
207
+
208
+ substElementTypes. push_back (substComponentType);
209
+ substConformances. push_back (substConformance);
210
+ } );
332
211
}
333
212
334
213
public:
335
214
void expand (PackType *origPackType) {
336
- for (unsigned i = 0 , e = origPackType->getNumElements (); i < e; ++i) {
337
- auto origElement = origPackType->getElementType (i);
215
+ assert (origPackType->getNumElements () == origConformances.size ());
338
216
339
- // Check if the original element is potentially being expanded.
340
- if (auto *origExpansion = origElement->getAs <PackExpansionType>()) {
341
- maybeExpandExpansion (origExpansion, i);
342
- continue ;
217
+ for (auto i : range (origPackType->getNumElements ())) {
218
+ auto origElementType = origPackType->getElementType (i);
219
+ if (auto *origExpansion = origElementType->getAs <PackExpansionType>()) {
220
+ substExpansion (origExpansion, origConformances[i]);
221
+ } else {
222
+ substScalar (origElementType, origConformances[i]);
343
223
}
344
-
345
- addScalar (origElement, i);
346
224
}
347
225
}
348
226
};
349
227
350
- class PackConformanceExpander : public PackExpander <PackConformanceExpander> {
351
- public:
352
- SmallVector<Type, 4 > substElements;
353
- SmallVector<ProtocolConformanceRef, 4 > substConformances;
354
-
355
- ArrayRef<ProtocolConformanceRef> origConformances;
356
-
357
- PackConformanceExpander (InFlightSubstitution &IFS,
358
- ArrayRef<ProtocolConformanceRef> origConformances)
359
- : PackExpander(IFS), origConformances(origConformances) {}
360
-
361
- void add (Type origType, Type substType, unsigned i) {
362
- substElements.push_back (substType);
363
-
364
- // FIXME: Pass down projection callbacks
365
- substConformances.push_back (origConformances[i].subst (
366
- origType, IFS));
367
- }
368
- };
369
-
370
- }
228
+ } // end anonymous namespace
371
229
372
230
ProtocolConformanceRef PackConformance::subst (TypeSubstitutionFn subs,
373
231
LookupConformanceFn conformances,
@@ -382,7 +240,7 @@ PackConformance::subst(InFlightSubstitution &IFS) const {
382
240
expander.expand (ConformingType);
383
241
384
242
auto &ctx = Protocol->getASTContext ();
385
- auto *substConformingType = PackType::get (ctx, expander.substElements );
243
+ auto *substConformingType = PackType::get (ctx, expander.substElementTypes );
386
244
387
245
auto substConformance = PackConformance::get (substConformingType, Protocol,
388
246
expander.substConformances );
0 commit comments