@@ -179,6 +179,46 @@ bool FulfillmentMap::searchTypeMetadata(IRGenModule &IGM, CanType type,
179179 return false ;
180180}
181181
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+
182222bool FulfillmentMap::searchConformance (
183223 IRGenModule &IGM, const ProtocolConformance *conformance,
184224 unsigned sourceIndex, MetadataPath &&path,
@@ -297,10 +337,8 @@ bool FulfillmentMap::searchNominalTypeMetadata(IRGenModule &IGM,
297337 MetadataPath argPath = path;
298338 argPath.addNominalTypeArgumentShapeComponent (reqtIndex);
299339
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));
304342 break ;
305343 }
306344 case GenericRequirement::Kind::Metadata:
@@ -310,22 +348,44 @@ bool FulfillmentMap::searchNominalTypeMetadata(IRGenModule &IGM,
310348 getPresumedMetadataStateForTypeArgument (metadataState);
311349 MetadataPath argPath = path;
312350 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);
315360 break ;
316361 }
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+ }
322378
323379 // Refine the path.
324380 MetadataPath argPath = path;
325381 argPath.addNominalTypeArgumentConformanceComponent (reqtIndex);
382+ if (packExpansionComponent)
383+ argPath.addPackExpansionPatternComponent (*packExpansionComponent);
326384
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);
329389 break ;
330390 }
331391 }
@@ -334,6 +394,33 @@ bool FulfillmentMap::searchNominalTypeMetadata(IRGenModule &IGM,
334394 return hadFulfillment;
335395}
336396
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+
337424// / Testify that there's a fulfillment at the given path.
338425bool FulfillmentMap::addFulfillment (GenericRequirement key,
339426 unsigned source,
0 commit comments