@@ -179,6 +179,46 @@ bool FulfillmentMap::searchTypeMetadata(IRGenModule &IGM, CanType type,
179
179
return false ;
180
180
}
181
181
182
+ static CanType getSingletonPackExpansionParameter (CanPackType packType,
183
+ const FulfillmentMap::InterestingKeysCallback &keys,
184
+ Optional<unsigned > &packExpansionComponent) {
185
+ if (packType->getNumElements () != 1 )
186
+ return CanType ();
187
+ auto expansion = dyn_cast<PackExpansionType>(packType.getElementType (0 ));
188
+ if (!expansion || !keys.isInterestingPackExpansion (expansion))
189
+ return CanType ();
190
+
191
+ packExpansionComponent = 0 ;
192
+ return expansion.getPatternType ();
193
+ }
194
+
195
+ bool FulfillmentMap::searchTypeMetadataPack (IRGenModule &IGM,
196
+ CanPackType packType,
197
+ IsExact_t isExact,
198
+ MetadataState metadataState,
199
+ unsigned source,
200
+ MetadataPath &&path,
201
+ const InterestingKeysCallback &keys) {
202
+ // We can fulfill pack parameters if the pack is a singleton pack
203
+ // expansion over one.
204
+ // TODO: we can also fulfill pack expansions if we can slice away
205
+ // constant-sized prefixes and suffixes.
206
+ Optional<unsigned > packExpansionComponent;
207
+ if (auto parameter = getSingletonPackExpansionParameter (packType, keys,
208
+ packExpansionComponent)) {
209
+ MetadataPath singletonPath = path;
210
+ singletonPath.addPackExpansionPatternComponent (*packExpansionComponent);
211
+ return addFulfillment (GenericRequirement::forMetadata (parameter),
212
+ source, std::move (singletonPath), metadataState);
213
+ }
214
+
215
+ // TODO: fulfill non-expansion metadata out of the pack
216
+
217
+ // TODO: fulfill the pack type itself
218
+
219
+ return false ;
220
+ }
221
+
182
222
bool FulfillmentMap::searchConformance (
183
223
IRGenModule &IGM, const ProtocolConformance *conformance,
184
224
unsigned sourceIndex, MetadataPath &&path,
@@ -297,10 +337,8 @@ bool FulfillmentMap::searchNominalTypeMetadata(IRGenModule &IGM,
297
337
MetadataPath argPath = path;
298
338
argPath.addNominalTypeArgumentShapeComponent (reqtIndex);
299
339
300
- // Add the fulfillment.
301
- hadFulfillment |= addFulfillment (GenericRequirement::forShape (arg),
302
- source, std::move (argPath),
303
- MetadataState::Complete);
340
+ hadFulfillment |= searchShapeRequirement (IGM, arg, source,
341
+ std::move (argPath));
304
342
break ;
305
343
}
306
344
case GenericRequirement::Kind::Metadata:
@@ -310,22 +348,44 @@ bool FulfillmentMap::searchNominalTypeMetadata(IRGenModule &IGM,
310
348
getPresumedMetadataStateForTypeArgument (metadataState);
311
349
MetadataPath argPath = path;
312
350
argPath.addNominalTypeArgumentComponent (reqtIndex);
313
- hadFulfillment |= searchTypeMetadata (
314
- IGM, arg, IsExact, argState, source, std::move (argPath), keys);
351
+
352
+ if (requirement.getKind () == GenericRequirement::Kind::Metadata)
353
+ hadFulfillment |=
354
+ searchTypeMetadata (IGM, arg, IsExact, argState,
355
+ source, std::move (argPath), keys);
356
+ else
357
+ hadFulfillment |=
358
+ searchTypeMetadataPack (IGM, cast<PackType>(arg), IsExact, argState,
359
+ source, std::move (argPath), keys);
315
360
break ;
316
361
}
317
- case GenericRequirement::Kind::WitnessTable:
318
- case GenericRequirement::Kind::WitnessTablePack: {
319
- // Ignore it unless the type itself is interesting.
320
- if (!keys.isInterestingType (arg))
321
- continue ;
362
+ case GenericRequirement::Kind::WitnessTablePack:
363
+ case GenericRequirement::Kind::WitnessTable: {
364
+ Optional<unsigned > packExpansionComponent;
365
+ if (requirement.getKind () == GenericRequirement::Kind::WitnessTable) {
366
+ // Ignore it unless the type itself is interesting.
367
+ if (!keys.isInterestingType (arg))
368
+ continue ;
369
+ } else {
370
+ // Ignore it unless the pack is a singleton pack expansion of a
371
+ // type parameter, in which case use that type below.
372
+ auto param =
373
+ getSingletonPackExpansionParameter (cast<PackType>(arg), keys,
374
+ packExpansionComponent);
375
+ if (!param) continue ;
376
+ arg = param;
377
+ }
322
378
323
379
// Refine the path.
324
380
MetadataPath argPath = path;
325
381
argPath.addNominalTypeArgumentConformanceComponent (reqtIndex);
382
+ if (packExpansionComponent)
383
+ argPath.addPackExpansionPatternComponent (*packExpansionComponent);
326
384
327
- hadFulfillment |= searchWitnessTable (IGM, arg, requirement.getProtocol (),
328
- source, std::move (argPath), keys);
385
+ // This code just handles packs directly.
386
+ hadFulfillment |=
387
+ searchWitnessTable (IGM, arg, requirement.getProtocol (),
388
+ source, std::move (argPath), keys);
329
389
break ;
330
390
}
331
391
}
@@ -334,6 +394,33 @@ bool FulfillmentMap::searchNominalTypeMetadata(IRGenModule &IGM,
334
394
return hadFulfillment;
335
395
}
336
396
397
+ bool FulfillmentMap::searchShapeRequirement (IRGenModule &IGM, CanType argType,
398
+ unsigned source, MetadataPath &&path) {
399
+ // argType is the substitution for a pack parameter, so it should always
400
+ // be a pack.
401
+ auto packType = cast<PackType>(argType);
402
+
403
+ // For now, don't try to fulfill shapes if this isn't a singleton
404
+ // pack containing a pack expansion. In theory, though, as long as
405
+ // there aren't expansions over pack parameters with different shapes,
406
+ // we should always be able to turn this into the equation
407
+ // `ax + b = <fulfilled count>` and then solve that.
408
+ if (packType->getNumElements () != 1 )
409
+ return false ;
410
+ auto expansion =
411
+ dyn_cast<PackExpansionType>(packType.getElementType (0 ));
412
+ if (!expansion)
413
+ return false ;
414
+
415
+ path.addPackExpansionCountComponent (0 );
416
+
417
+ auto parameter = expansion.getCountType ();
418
+
419
+ // Add the fulfillment.
420
+ return addFulfillment (GenericRequirement::forShape (parameter),
421
+ source, std::move (path), MetadataState::Complete);
422
+ }
423
+
337
424
// / Testify that there's a fulfillment at the given path.
338
425
bool FulfillmentMap::addFulfillment (GenericRequirement key,
339
426
unsigned source,
0 commit comments