Skip to content

Commit ebb99e5

Browse files
committed
SILGen: Wrap captures of parameter packs inside tuples
Fixes rdar://problem/108481933.
1 parent a76723f commit ebb99e5

File tree

7 files changed

+283
-74
lines changed

7 files changed

+283
-74
lines changed

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,6 +1929,16 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
19291929
auto type = VD->getInterfaceType();
19301930
auto canType = type->getReducedType(origGenericSig);
19311931

1932+
// If we're capturing a parameter pack, wrap it in a tuple.
1933+
if (isa<PackExpansionType>(canType)) {
1934+
assert(!cast<ParamDecl>(VD)->supportsMutation() &&
1935+
"Cannot capture a pack as an lvalue");
1936+
1937+
SmallVector<TupleTypeElt, 1> elts;
1938+
elts.push_back(canType);
1939+
canType = CanTupleType(TupleType::get(elts, TC.Context));
1940+
}
1941+
19321942
auto &loweredTL =
19331943
TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType,
19341944
expansion);

lib/SILGen/SILGenFunction.cpp

Lines changed: 80 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -505,10 +505,24 @@ void SILGenFunction::emitCaptures(SILLocation loc,
505505
}
506506

507507
auto *vd = cast<VarDecl>(capture.getDecl());
508-
auto type = FunctionDC->mapTypeIntoContext(
509-
vd->getInterfaceType());
508+
509+
auto interfaceType = vd->getInterfaceType();
510+
511+
bool isPack = false;
512+
if (interfaceType->is<PackExpansionType>()) {
513+
assert(!vd->supportsMutation() &&
514+
"Cannot capture a pack as an lvalue");
515+
516+
SmallVector<TupleTypeElt, 1> elts;
517+
elts.push_back(interfaceType);
518+
interfaceType = TupleType::get(elts, getASTContext());
519+
520+
isPack = true;
521+
}
522+
523+
auto type = FunctionDC->mapTypeIntoContext(interfaceType);
510524
auto valueType = FunctionDC->mapTypeIntoContext(
511-
vd->getValueInterfaceType());
525+
interfaceType->getReferenceStorageReferent());
512526

513527
//
514528
// If we haven't emitted the captured value yet, we're forming a closure
@@ -571,8 +585,7 @@ void SILGenFunction::emitCaptures(SILLocation loc,
571585

572586
// Get an address value for a SILValue if it is address only in an type
573587
// expansion context without opaque archetype substitution.
574-
auto getAddressValue = [&](VarLoc entryVarLoc) -> SILValue {
575-
SILValue entryValue = entryVarLoc.value;
588+
auto getAddressValue = [&](SILValue entryValue, bool forceCopy) -> SILValue {
576589
if (SGM.M.useLoweredAddresses()
577590
&& SGM.Types
578591
.getTypeLowering(
@@ -582,32 +595,62 @@ void SILGenFunction::emitCaptures(SILLocation loc,
582595
.isAddressOnly()
583596
&& !entryValue->getType().isAddress()) {
584597

598+
assert(!isPack);
599+
585600
auto addr = emitTemporaryAllocation(vd, entryValue->getType(), false,
586601
false, /*generateDebugInfo*/ false);
587602
auto val = B.emitCopyValueOperation(loc, entryValue);
588603
auto &lowering = getTypeLowering(entryValue->getType());
589604
lowering.emitStore(B, loc, val, addr, StoreOwnershipQualifier::Init);
590-
entryValue = addr;
591-
enterDestroyCleanup(addr);
605+
606+
if (!forceCopy)
607+
enterDestroyCleanup(addr);
608+
return addr;
609+
610+
} else if (isPack) {
611+
SILType ty = getLoweredType(valueType).getObjectType();
612+
auto addr = B.createAllocStack(loc, ty);
613+
enterDeallocStackCleanup(addr);
614+
615+
auto formalPackType = cast<TupleType>(valueType->getCanonicalType())
616+
.getInducedPackType();
617+
copyPackElementsToTuple(loc, addr, entryValue, formalPackType);
618+
619+
if (!forceCopy)
620+
enterDestroyCleanup(addr);
621+
return addr;
622+
623+
} else if (forceCopy) {
624+
// We cannot pass a valid SILDebugVariable while creating the temp here
625+
// See rdar://60425582
626+
auto addr = B.createAllocStack(loc, entryValue->getType().getObjectType());
627+
enterDeallocStackCleanup(addr);
628+
B.createCopyAddr(loc, entryValue, addr, IsNotTake, IsInitialization);
629+
return addr;
630+
631+
} else {
632+
return entryValue;
592633
}
593-
return entryValue;
594634
};
595635

596636
auto Entry = found->second;
637+
auto val = Entry.value;
638+
597639
switch (SGM.Types.getDeclCaptureKind(capture, expansion)) {
598640
case CaptureKind::Constant: {
641+
assert(!isPack);
642+
599643
// let declarations.
600644
auto &tl = getTypeLowering(valueType);
601-
SILValue Val = Entry.value;
602645
bool eliminateMoveOnlyWrapper =
603-
Val->getType().isMoveOnlyWrapped() &&
604-
!vd->getInterfaceType()->is<SILMoveOnlyWrappedType>();
646+
val->getType().isMoveOnlyWrapped() &&
647+
!interfaceType->is<SILMoveOnlyWrappedType>();
605648

606-
if (!Val->getType().isAddress()) {
649+
if (!val->getType().isAddress()) {
607650
// Our 'let' binding can guarantee the lifetime for the callee,
608651
// if we don't need to do anything more to it.
609652
if (canGuarantee && !vd->getInterfaceType()->is<ReferenceStorageType>()) {
610-
auto guaranteed = ManagedValue::forUnmanaged(Val).borrow(*this, loc);
653+
auto guaranteed = ManagedValue::forUnmanaged(val).borrow(*this, loc);
611654
if (eliminateMoveOnlyWrapper)
612655
guaranteed = B.createGuaranteedMoveOnlyWrapperToCopyableValue(
613656
loc, guaranteed);
@@ -616,64 +659,63 @@ void SILGenFunction::emitCaptures(SILLocation loc,
616659
}
617660

618661
// Just copy a by-val let.
619-
Val = B.emitCopyValueOperation(loc, Val);
662+
val = B.emitCopyValueOperation(loc, val);
620663
// If we need to unwrap a moveonlywrapped value, do so now but in an
621664
// owned way to ensure that the partial apply is viewed as a semantic
622665
// use of the value.
623666
if (eliminateMoveOnlyWrapper)
624-
Val = B.createOwnedMoveOnlyWrapperToCopyableValue(loc, Val);
667+
val = B.createOwnedMoveOnlyWrapperToCopyableValue(loc, val);
625668
} else {
626669
// If we have a mutable binding for a 'let', such as 'self' in an
627670
// 'init' method, load it.
628-
if (Val->getType().isMoveOnly()) {
629-
Val = B.createMarkMustCheckInst(
630-
loc, Val,
671+
if (val->getType().isMoveOnly()) {
672+
val = B.createMarkMustCheckInst(
673+
loc, val,
631674
MarkMustCheckInst::CheckKind::AssignableButNotConsumable);
632675
}
633-
Val = emitLoad(loc, Val, tl, SGFContext(), IsNotTake).forward(*this);
676+
val = emitLoad(loc, val, tl, SGFContext(), IsNotTake).forward(*this);
634677
}
635678

636679
// If we're capturing an unowned pointer by value, we will have just
637680
// loaded it into a normal retained class pointer, but we capture it as
638681
// an unowned pointer. Convert back now.
639-
if (vd->getInterfaceType()->is<ReferenceStorageType>())
640-
Val = emitConversionFromSemanticValue(loc, Val, getLoweredType(type));
682+
if (interfaceType->is<ReferenceStorageType>())
683+
val = emitConversionFromSemanticValue(loc, val, getLoweredType(type));
641684

642-
capturedArgs.push_back(emitManagedRValueWithCleanup(Val));
685+
capturedArgs.push_back(emitManagedRValueWithCleanup(val));
643686
break;
644687
}
645688
case CaptureKind::Immutable: {
646689
if (canGuarantee) {
647690
// No-escaping stored declarations are captured as the
648691
// address of the value.
649-
auto entryValue = getAddressValue(Entry);
650-
capturedArgs.push_back(ManagedValue::forBorrowedRValue(entryValue));
692+
auto addr = getAddressValue(val, /*forceCopy=*/false);
693+
capturedArgs.push_back(ManagedValue::forBorrowedRValue(addr));
651694
}
652695
else if (!silConv.useLoweredAddresses()) {
653696
capturedArgs.push_back(
654-
B.createCopyValue(loc, ManagedValue::forUnmanaged(Entry.value)));
697+
B.createCopyValue(loc, ManagedValue::forUnmanaged(val)));
655698
} else {
656-
auto entryValue = getAddressValue(Entry);
657-
// We cannot pass a valid SILDebugVariable while creating the temp here
658-
// See rdar://60425582
659-
auto addr = B.createAllocStack(loc, entryValue->getType().getObjectType());
660-
enterDeallocStackCleanup(addr);
661-
B.createCopyAddr(loc, entryValue, addr, IsNotTake, IsInitialization);
699+
auto addr = getAddressValue(val, /*forceCopy=*/true);
662700
capturedArgs.push_back(ManagedValue::forLValue(addr));
663701
}
664702
break;
665703
}
666704
case CaptureKind::StorageAddress: {
667-
auto entryValue = getAddressValue(Entry);
705+
assert(!isPack);
706+
707+
auto addr = getAddressValue(val, /*forceCopy=*/false);
668708
// No-escaping stored declarations are captured as the
669709
// address of the value.
670-
assert(entryValue->getType().isAddress() && "no address for captured var!");
671-
capturedArgs.push_back(ManagedValue::forLValue(entryValue));
710+
assert(addr->getType().isAddress() && "no address for captured var!");
711+
capturedArgs.push_back(ManagedValue::forLValue(addr));
672712
break;
673713
}
674714

675715
case CaptureKind::Box: {
676-
auto entryValue = getAddressValue(Entry);
716+
assert(!isPack);
717+
718+
auto entryValue = getAddressValue(val, /*forceCopy=*/false);
677719
// LValues are captured as both the box owning the value and the
678720
// address of the value.
679721
assert(entryValue->getType().isAddress() && "no address for captured var!");
@@ -722,7 +764,9 @@ void SILGenFunction::emitCaptures(SILLocation loc,
722764
break;
723765
}
724766
case CaptureKind::ImmutableBox: {
725-
auto entryValue = getAddressValue(Entry);
767+
assert(!isPack);
768+
769+
auto entryValue = getAddressValue(val, /*forceCopy=*/false);
726770
// LValues are captured as both the box owning the value and the
727771
// address of the value.
728772
assert(entryValue->getType().isAddress() &&

lib/SILGen/SILGenFunction.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2485,6 +2485,16 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
24852485
unsigned componentIndex,
24862486
SILValue currentIndexWithinComponent);
24872487

2488+
/// Copy the elements of a pack, which must consist of a single pack expansion,
2489+
/// into a tuple value having the same pack expansion and its sole element type.
2490+
void copyPackElementsToTuple(SILLocation loc, SILValue tupleAddr, SILValue pack,
2491+
CanPackType formalPackType);
2492+
2493+
/// Initialize a pack with the addresses of the elements of a tuple, which must
2494+
/// consist of a single pack expansion.
2495+
void projectTupleElementsToPack(SILLocation loc, SILValue tupleAddr, SILValue pack,
2496+
CanPackType formalPackType);
2497+
24882498
/// Return an owned managed value for \p value that is cleaned up using an end_lifetime instruction.
24892499
///
24902500
/// The end_lifetime cleanup is not placed into the ManagedValue itself and

lib/SILGen/SILGenPack.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,49 @@ void SILGenFunction::emitPartialDestroyRemainingTuple(SILLocation loc,
521521
});
522522
}
523523

524+
void SILGenFunction::copyPackElementsToTuple(SILLocation loc,
525+
SILValue tupleAddr,
526+
SILValue pack,
527+
CanPackType formalPackType) {
528+
auto pair = createOpenedElementValueEnvironment(
529+
tupleAddr->getType().getTupleElementType(/*componentIndex=*/0));
530+
auto elementEnv = pair.first;
531+
auto elementTy = pair.second;
532+
533+
emitDynamicPackLoop(
534+
loc, formalPackType, /*componentIndex=*/0, elementEnv,
535+
[&](SILValue indexWithinComponent,
536+
SILValue packExpansionIndex,
537+
SILValue packIndex) {
538+
auto packEltAddr = B.createPackElementGet(
539+
loc, packIndex, pack, elementTy);
540+
auto tupleEltAddr = B.createTuplePackElementAddr(
541+
loc, packIndex, tupleAddr, elementTy);
542+
B.createCopyAddr(loc, packEltAddr, tupleEltAddr,
543+
IsNotTake, IsInitialization);
544+
});
545+
}
546+
547+
void SILGenFunction::projectTupleElementsToPack(SILLocation loc,
548+
SILValue tupleAddr,
549+
SILValue pack,
550+
CanPackType formalPackType) {
551+
auto pair = createOpenedElementValueEnvironment(
552+
tupleAddr->getType().getTupleElementType(/*componentIndex=*/0));
553+
auto elementEnv = pair.first;
554+
auto elementTy = pair.second;
555+
556+
emitDynamicPackLoop(
557+
loc, formalPackType, /*componentIndex=*/0, elementEnv,
558+
[&](SILValue indexWithinComponent,
559+
SILValue packExpansionIndex,
560+
SILValue packIndex) {
561+
auto tupleEltAddr = B.createTuplePackElementAddr(
562+
loc, packIndex, tupleAddr, elementTy);
563+
B.createPackElementSet(loc, tupleEltAddr, packIndex, pack);
564+
});
565+
}
566+
524567
void SILGenFunction::emitDynamicPackLoop(SILLocation loc,
525568
CanPackType formalPackType,
526569
unsigned componentIndex,

0 commit comments

Comments
 (0)