@@ -283,7 +283,7 @@ LayoutConstraint AbstractionPattern::getLayoutConstraint() const {
283283 }
284284}
285285
286- bool AbstractionPattern::matchesTuple (CanTupleType substType) const {
286+ bool AbstractionPattern::matchesTuple (CanType substType) const {
287287 switch (getKind ()) {
288288 case Kind::Invalid:
289289 llvm_unreachable (" querying invalid abstraction pattern!" );
@@ -311,11 +311,19 @@ bool AbstractionPattern::matchesTuple(CanTupleType substType) const {
311311 return false ;
312312 LLVM_FALLTHROUGH;
313313 case Kind::Tuple: {
314+ if (getVanishingTupleElementPatternType ()) {
315+ // TODO: recurse into elements.
316+ return true ;
317+ }
318+
319+ auto substTupleType = dyn_cast<TupleType>(substType);
320+ if (!substTupleType) return false ;
321+
314322 size_t nextSubstIndex = 0 ;
315323 auto nextComponentIsAcceptable = [&](bool isPackExpansion) -> bool {
316- if (nextSubstIndex == substType ->getNumElements ())
324+ if (nextSubstIndex == substTupleType ->getNumElements ())
317325 return false ;
318- auto substComponentType = substType .getElementType (nextSubstIndex++);
326+ auto substComponentType = substTupleType .getElementType (nextSubstIndex++);
319327 return (isPackExpansion == isa<PackExpansionType>(substComponentType));
320328 };
321329 for (auto elt : getTupleElementTypes ()) {
@@ -333,7 +341,7 @@ bool AbstractionPattern::matchesTuple(CanTupleType substType) const {
333341 return false ;
334342 }
335343 }
336- return nextSubstIndex == substType ->getNumElements ();
344+ return nextSubstIndex == substTupleType ->getNumElements ();
337345 }
338346 }
339347 llvm_unreachable (" bad kind" );
@@ -469,7 +477,63 @@ bool AbstractionPattern::doesTupleContainPackExpansionType() const {
469477 llvm_unreachable (" bad kind" );
470478}
471479
472- void AbstractionPattern::forEachTupleElement (CanTupleType substType,
480+ Optional<AbstractionPattern>
481+ AbstractionPattern::getVanishingTupleElementPatternType () const {
482+ if (!isTuple ()) return None;
483+ if (!GenericSubs) return None;
484+
485+ // Substitution causes tuples to vanish when substituting the elements
486+ // produces a singleton tuple and it didn't start that way.
487+
488+ auto numOrigElts = getNumTupleElements ();
489+
490+ // Track whether we've found a single element.
491+ Optional<AbstractionPattern> singletonEltType;
492+ bool hadOrigExpansion = false ;
493+ for (auto index : range (numOrigElts)) {
494+ auto eltType = getTupleElementType (index);
495+
496+ // If this pattern isn't a pack expansion, we've got a new candidate
497+ // singleton. If this is the second such candidate, of course, it's
498+ // not a singleton.
499+ if (!eltType.isPackExpansion ()) {
500+ if (singletonEltType) return None;
501+ singletonEltType = eltType;
502+
503+ // Otherwise, check what the expansion shape expands to.
504+ } else {
505+ hadOrigExpansion = true ;
506+
507+ auto expansionType = cast<PackExpansionType>(eltType.getType ());
508+ auto substShape = cast<PackType>(
509+ expansionType.getCountType ().subst (GenericSubs)->getCanonicalType ());
510+ auto expansionCount = substShape->getNumElements ();
511+
512+ // If it expands to multiple elements or to a single expansion, we
513+ // won't have a singleton tuple. If it expands to a single scalar
514+ // element, this is a singleton candidate.
515+ if (expansionCount > 1 ) {
516+ return None;
517+ } else if (expansionCount == 1 ) {
518+ auto substExpansion =
519+ dyn_cast<PackExpansionType>(substShape.getElementType (0 ));
520+ if (substExpansion)
521+ return None;
522+ if (singletonEltType)
523+ return None;
524+ singletonEltType = eltType.getPackExpansionPatternType ();
525+ }
526+ }
527+ }
528+
529+ // If we found a singleton scalar element, and we didn't start with
530+ // a singleton element, that's the index we want to return.
531+ if (singletonEltType && !(numOrigElts == 1 && !hadOrigExpansion))
532+ return singletonEltType;
533+ return None;
534+ }
535+
536+ void AbstractionPattern::forEachTupleElement (CanType substType,
473537 llvm::function_ref<void (TupleElementGenerator &)> handleElement) const {
474538 TupleElementGenerator elt (*this , substType);
475539 for (; !elt.isFinished (); elt.advance ()) {
@@ -480,35 +544,46 @@ void AbstractionPattern::forEachTupleElement(CanTupleType substType,
480544
481545TupleElementGenerator::TupleElementGenerator (
482546 AbstractionPattern origTupleType,
483- CanTupleType substTupleType )
484- : origTupleType(origTupleType), substTupleType(substTupleType ) {
547+ CanType substType )
548+ : origTupleType(origTupleType), substType(substType ) {
485549 assert (origTupleType.isTuple ());
486- assert (origTupleType.matchesTuple (substTupleType ));
550+ assert (origTupleType.matchesTuple (substType ));
487551
552+ origTupleVanishes =
553+ origTupleType.getVanishingTupleElementPatternType ().hasValue ();
488554 origTupleTypeIsOpaque = origTupleType.isOpaqueTuple ();
489555 numOrigElts = origTupleType.getNumTupleElements ();
490556
491557 if (!isFinished ()) loadElement ();
492558}
493559
494- void AbstractionPattern::forEachExpandedTupleElement (CanTupleType substType,
560+ void AbstractionPattern::forEachExpandedTupleElement (CanType substType,
495561 llvm::function_ref<void (AbstractionPattern origEltType,
496562 CanType substEltType,
497563 const TupleTypeElt &elt)>
498564 handleElement) const {
499565 assert (matchesTuple (substType));
500566
501- auto substEltTypes = substType.getElementTypes ();
502-
503567 // Handle opaque patterns by just iterating the substituted components.
504568 if (!isTuple ()) {
569+ auto substTupleType = cast<TupleType>(substType);
570+ auto substEltTypes = substTupleType.getElementTypes ();
505571 for (auto i : indices (substEltTypes)) {
506572 handleElement (getTupleElementType (i), substEltTypes[i],
507- substType ->getElement (i));
573+ substTupleType ->getElement (i));
508574 }
509575 return ;
510576 }
511577
578+ // For vanishing tuples, just call the callback once.
579+ if (auto origEltType = getVanishingTupleElementPatternType ()) {
580+ handleElement (*origEltType, substType, TupleTypeElt (substType));
581+ return ;
582+ }
583+
584+ auto substTupleType = cast<TupleType>(substType);
585+ auto substEltTypes = substTupleType.getElementTypes ();
586+
512587 // For non-opaque patterns, we have to iterate the original components
513588 // in order to match things up properly, but we'll still end up calling
514589 // once per substituted element.
@@ -517,7 +592,7 @@ void AbstractionPattern::forEachExpandedTupleElement(CanTupleType substType,
517592 auto origEltType = getTupleElementType (origEltIndex);
518593 if (!origEltType.isPackExpansion ()) {
519594 handleElement (origEltType, substEltTypes[substEltIndex],
520- substType ->getElement (substEltIndex));
595+ substTupleType ->getElement (substEltIndex));
521596 substEltIndex++;
522597 } else {
523598 auto origPatternType = origEltType.getPackExpansionPatternType ();
@@ -532,7 +607,8 @@ void AbstractionPattern::forEachExpandedTupleElement(CanTupleType substType,
532607 // be misleading in one way or another.
533608 handleElement (isa<PackExpansionType>(substEltType)
534609 ? origEltType : origPatternType,
535- substEltType, substType->getElement (substEltIndex));
610+ substEltType,
611+ substTupleType->getElement (substEltIndex));
536612 substEltIndex++;
537613 }
538614 }
0 commit comments