@@ -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,
@@ -291,33 +331,94 @@ bool FulfillmentMap::searchNominalTypeMetadata(IRGenModule &IGM,
291331 if (!keys.hasInterestingType (arg))
292332 continue ;
293333
294- // If the fulfilled value is type metadata, refine the path.
295- if (requirement.isMetadata ()) {
334+ switch (requirement.getKind ()) {
335+ case GenericRequirement::Kind::Shape: {
336+ // If the fulfilled value is a shape class, refine the path.
337+ MetadataPath argPath = path;
338+ argPath.addNominalTypeArgumentShapeComponent (reqtIndex);
339+
340+ hadFulfillment |= searchShapeRequirement (IGM, arg, source,
341+ std::move (argPath));
342+ break ;
343+ }
344+ case GenericRequirement::Kind::Metadata:
345+ case GenericRequirement::Kind::MetadataPack: {
346+ // If the fulfilled value is type metadata, refine the path.
296347 auto argState =
297348 getPresumedMetadataStateForTypeArgument (metadataState);
298349 MetadataPath argPath = path;
299350 argPath.addNominalTypeArgumentComponent (reqtIndex);
300- hadFulfillment |= searchTypeMetadata (
301- IGM, arg, IsExact, argState, source, std::move (argPath), keys);
302- continue ;
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);
360+ break ;
303361 }
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+ }
304378
305- // Otherwise, it's a conformance.
306- assert (requirement.isWitnessTable ());
379+ // Refine the path.
380+ MetadataPath argPath = path;
381+ argPath.addNominalTypeArgumentConformanceComponent (reqtIndex);
382+ if (packExpansionComponent)
383+ argPath.addPackExpansionPatternComponent (*packExpansionComponent);
384+
385+ // This code just handles packs directly.
386+ hadFulfillment |=
387+ searchWitnessTable (IGM, arg, requirement.getProtocol (),
388+ source, std::move (argPath), keys);
389+ break ;
390+ }
391+ }
392+ }
307393
308- // Ignore it unless the type itself is interesting.
309- if (!keys.isInterestingType (arg))
310- continue ;
394+ return hadFulfillment;
395+ }
311396
312- // Refine the path.
313- MetadataPath argPath = path;
314- argPath.addNominalTypeArgumentConformanceComponent (reqtIndex);
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 ;
315414
316- hadFulfillment |= searchWitnessTable (IGM, arg, requirement.getProtocol (),
317- source, std::move (argPath), keys);
318- }
415+ path.addPackExpansionCountComponent (0 );
319416
320- return hadFulfillment;
417+ auto parameter = expansion.getCountType ();
418+
419+ // Add the fulfillment.
420+ return addFulfillment (GenericRequirement::forShape (parameter),
421+ source, std::move (path), MetadataState::Complete);
321422}
322423
323424// / Testify that there's a fulfillment at the given path.
0 commit comments