Skip to content

Commit 2d72da3

Browse files
committed
Add a few convenience functions for inducing pack types from tuples
and lowered pack types. The "approximate" thing is kindof a representational/testing wart. Really, all that we care about is that we have a formal pack type with the right shape. (We don't *really* need a formal pack type --- we could use anything that can represent the shape --- but we seem to be standardizing on `PackType` for that.) We could just use the reduced shape for that, but for some reason I've been resisting that. Not sure I have a compelling reason, though, and if we decide to use reduced shapes, we can eliminate the approximate formal packs stuff. Inducing packs from tuple slices is a more permanently-useful thing.
1 parent bea923a commit 2d72da3

File tree

3 files changed

+97
-48
lines changed

3 files changed

+97
-48
lines changed

include/swift/AST/Types.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2456,15 +2456,30 @@ BEGIN_CAN_TYPE_WRAPPER(TupleType, Type)
24562456
return containsPackExpansionTypeImpl(*this);
24572457
}
24582458

2459+
/// Induce a pack type from the elements of this tuple type.
2460+
inline CanTypeWrapper<PackType> getInducedPackType() const;
2461+
24592462
/// Induce a pack type from a range of the elements of this tuple type.
24602463
inline CanTypeWrapper<PackType>
24612464
getInducedPackType(unsigned start, unsigned count) const;
24622465

2466+
/// Induce a formal pack type with the same shape as the elements
2467+
/// of this lowered tuple type, making a best effort to use the same
2468+
/// element types.
2469+
inline CanTypeWrapper<PackType>
2470+
getInducedApproximateFormalPackType() const;
2471+
24632472
private:
24642473
static bool containsPackExpansionTypeImpl(CanTupleType tuple);
24652474

2475+
static CanTypeWrapper<PackType>
2476+
getInducedPackTypeImpl(CanTupleType tuple);
2477+
24662478
static CanTypeWrapper<PackType>
24672479
getInducedPackTypeImpl(CanTupleType tuple, unsigned start, unsigned count);
2480+
2481+
static CanTypeWrapper<PackType>
2482+
getInducedApproximateFormalPackTypeImpl(CanTupleType tuple);
24682483
END_CAN_TYPE_WRAPPER(TupleType, Type)
24692484

24702485
/// UnboundGenericType - Represents a generic type where the type arguments have
@@ -5355,6 +5370,11 @@ class SILPackType final : public TypeBase, public llvm::FoldingSetNode,
53555370
/// as the shape, not a SIL pack type.
53565371
CanTypeWrapper<PackType> getReducedShape() const;
53575372

5373+
/// Construct a formal pack type with the same shape as this
5374+
/// lowered pack type, making a best effort to use the same element
5375+
/// types.
5376+
CanTypeWrapper<PackType> getApproximateFormalPackType() const;
5377+
53585378
bool containsPackExpansionType() const;
53595379

53605380
void Profile(llvm::FoldingSetNodeID &ID) const {
@@ -6841,11 +6861,20 @@ BEGIN_CAN_TYPE_WRAPPER(PackType, Type)
68416861
}
68426862
END_CAN_TYPE_WRAPPER(PackType, Type)
68436863

6864+
inline CanPackType CanTupleType::getInducedPackType() const {
6865+
return getInducedPackTypeImpl(*this);
6866+
}
6867+
68446868
inline CanPackType
68456869
CanTupleType::getInducedPackType(unsigned start, unsigned end) const {
68466870
return getInducedPackTypeImpl(*this, start, end);
68476871
}
68486872

6873+
inline CanPackType
6874+
CanTupleType::getInducedApproximateFormalPackType() const {
6875+
return getInducedApproximateFormalPackTypeImpl(*this);
6876+
}
6877+
68496878
/// PackExpansionType - The interface type of the explicit expansion of a
68506879
/// corresponding set of variadic generic parameters.
68516880
///

lib/AST/ParameterPack.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,9 +478,76 @@ bool SILPackType::containsPackExpansionType() const {
478478
return false;
479479
}
480480

481+
CanPackType
482+
CanTupleType::getInducedPackTypeImpl(CanTupleType tuple) {
483+
return getInducedPackTypeImpl(tuple, 0, tuple->getNumElements());
484+
}
485+
481486
CanPackType
482487
CanTupleType::getInducedPackTypeImpl(CanTupleType tuple, unsigned start, unsigned count) {
483488
assert(start + count <= tuple->getNumElements() && "range out of range");
484489
auto &ctx = tuple->getASTContext();
485490
return CanPackType::get(ctx, tuple.getElementTypes().slice(start, count));
486491
}
492+
493+
static CanType getApproximateFormalElementType(const ASTContext &ctx,
494+
CanType loweredEltType) {
495+
CanType formalEltType = TupleType::getEmpty(ctx);
496+
if (auto expansion = dyn_cast<PackExpansionType>(loweredEltType))
497+
formalEltType = CanPackExpansionType::get(formalEltType,
498+
expansion.getCountType());
499+
return formalEltType;
500+
}
501+
502+
template <class Collection>
503+
static CanPackType getApproximateFormalPackType(const ASTContext &ctx,
504+
Collection loweredEltTypes) {
505+
// Build an array of formal element types, but be lazy about it:
506+
// use the original array unless we see an element type that doesn't
507+
// work as a legal format type.
508+
Optional<SmallVector<CanType, 4>> formalEltTypes;
509+
for (auto i : indices(loweredEltTypes)) {
510+
auto loweredEltType = loweredEltTypes[i];
511+
bool isLegal = loweredEltType->isLegalFormalType();
512+
513+
// If the type isn't legal as a formal type, substitute the empty
514+
// tuple type (or an invariant expansion of it over the count type).
515+
CanType formalEltType = loweredEltType;
516+
if (!isLegal) {
517+
formalEltType = getApproximateFormalElementType(ctx, loweredEltType);
518+
}
519+
520+
// If we're already building an array, unconditionally append to it.
521+
// Otherwise, if the type isn't legal, build the array up to this
522+
// point and then append. Otherwise, we're still being lazy.
523+
if (formalEltTypes) {
524+
formalEltTypes->push_back(formalEltType);
525+
} else if (!isLegal) {
526+
formalEltTypes.emplace();
527+
formalEltTypes->reserve(loweredEltTypes.size());
528+
formalEltTypes->append(loweredEltTypes.begin(),
529+
loweredEltTypes.begin() + i);
530+
formalEltTypes->push_back(formalEltType);
531+
}
532+
533+
assert(isLegal || formalEltTypes.hasValue());
534+
}
535+
536+
// Use the array we built if we made one (if we ever saw a non-legal
537+
// element type).
538+
if (formalEltTypes) {
539+
return CanPackType::get(ctx, *formalEltTypes);
540+
} else {
541+
return CanPackType::get(ctx, loweredEltTypes);
542+
}
543+
}
544+
545+
CanPackType SILPackType::getApproximateFormalPackType() const {
546+
return ::getApproximateFormalPackType(getASTContext(), getElementTypes());
547+
}
548+
549+
CanPackType
550+
CanTupleType::getInducedApproximateFormalPackTypeImpl(CanTupleType tuple) {
551+
return ::getApproximateFormalPackType(tuple->getASTContext(),
552+
tuple.getElementTypes());
553+
}

lib/SILGen/SILGenPack.cpp

Lines changed: 1 addition & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -194,53 +194,6 @@ void SILGenFunction::emitDestroyPack(SILLocation loc, SILValue packAddr,
194194
}
195195
}
196196

197-
static CanPackType getInducedFormalPackType(CanSILPackType packType) {
198-
auto &ctx = packType->getASTContext();
199-
auto loweredEltTypes = packType.getElementTypes();
200-
201-
// Build an array of formal element types, but be lazy about it:
202-
// use the original array unless we see an element type that doesn't
203-
// work as a legal format type.
204-
Optional<SmallVector<CanType, 4>> formalEltTypes;
205-
for (auto i : indices(loweredEltTypes)) {
206-
auto loweredEltType = loweredEltTypes[i];
207-
bool isLegal = loweredEltType->isLegalFormalType();
208-
209-
// If the type isn't legal as a formal type, substitute the empty
210-
// tuple type (or an invariant expansion of it over the count type).
211-
CanType formalEltType = loweredEltType;
212-
if (!isLegal) {
213-
formalEltType = TupleType::getEmpty(ctx);
214-
if (auto expansion = dyn_cast<PackExpansionType>(loweredEltType))
215-
formalEltType = CanPackExpansionType::get(formalEltType,
216-
expansion.getCountType());
217-
}
218-
219-
// If we're already building an array, unconditionally append to it.
220-
// Otherwise, if the type isn't legal, build the array up to this
221-
// point and then append. Otherwise, we're still being lazy.
222-
if (formalEltTypes) {
223-
formalEltTypes->push_back(formalEltType);
224-
} else if (!isLegal) {
225-
formalEltTypes.emplace();
226-
formalEltTypes->reserve(loweredEltTypes.size());
227-
formalEltTypes->append(loweredEltTypes.begin(),
228-
loweredEltTypes.begin() + i);
229-
formalEltTypes->push_back(formalEltType);
230-
}
231-
232-
assert(isLegal || formalEltTypes.hasValue());
233-
}
234-
235-
// Use the array we built if we made one (if we ever saw a non-legal
236-
// element type).
237-
if (formalEltTypes) {
238-
return CanPackType::get(ctx, *formalEltTypes);
239-
} else {
240-
return CanPackType::get(ctx, loweredEltTypes);
241-
}
242-
}
243-
244197
ManagedValue
245198
SILGenFunction::emitManagedPackWithCleanup(SILValue addr,
246199
CanPackType formalPackType) {
@@ -252,7 +205,7 @@ SILGenFunction::emitManagedPackWithCleanup(SILValue addr,
252205
// the lowered pack type.
253206
auto packType = addr->getType().castTo<SILPackType>();
254207
if (!formalPackType)
255-
formalPackType = getInducedFormalPackType(packType);
208+
formalPackType = packType->getApproximateFormalPackType();
256209

257210
// Enter a cleanup for the pack.
258211
auto cleanup = enterDestroyPackCleanup(addr, formalPackType);

0 commit comments

Comments
 (0)