Skip to content

Commit 746aa1f

Browse files
committed
Model Pack Types
A pack type looks a lot like a tuple in the surface language, except there is no way for the user to spell a pack. Pack types are created by the solver when it encounters an apply of a variadic generic function, as in ``` func print<T...>(_ xs: T...) {} // Creates a pack type <String, Int, String> print("Macs say Hello in", 42, " different languages") ``` Pack types substituted into the variadic generic arguments of a PackExpansionType "trip" the pack expansion and cause it to produce a new pack type with the pack expansion pattern applied. ``` typealias Foo<T...> = (T?...) Foo<Int, String, Int> // Forces expansion to (Int?, String?, Int?) ```
1 parent 99f6c3e commit 746aa1f

19 files changed

+275
-1
lines changed

include/swift/AST/ASTContext.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,7 @@ class ASTContext final {
848848
const CanType TheErrorType; /// This is the ErrorType singleton.
849849
const CanType TheUnresolvedType; /// This is the UnresolvedType singleton.
850850
const CanType TheEmptyTupleType; /// This is '()', aka Void
851+
const CanType TheEmptyPackType;
851852
const CanType TheAnyType; /// This is 'Any', the empty protocol composition
852853
#define SINGLETON_TYPE(SHORT_ID, ID) \
853854
const CanType The##SHORT_ID##Type;

include/swift/AST/TypeDifferenceVisitor.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ class CanTypeDifferenceVisitor : public CanTypePairVisitor<Impl, bool> {
130130
return asImpl().visit(type1.getElementType(), type2.getElementType());
131131
}
132132

133+
bool visitPackType(CanPackType type1, CanPackType type2) {
134+
return visitComponentArray(type1, type2,
135+
type1->getElementTypes(),
136+
type2->getElementTypes());
137+
}
133138
bool visitTupleType(CanTupleType type1, CanTupleType type2) {
134139
return visitComponentArray(type1, type2,
135140
type1->getElements(), type2->getElements());

include/swift/AST/TypeMatcher.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,29 @@ class TypeMatcher {
143143
return mismatch(firstTuple.getPointer(), secondType, sugaredFirstType);
144144
}
145145

146+
bool visitPackType(CanPackType firstTuple, Type secondType,
147+
Type sugaredFirstType) {
148+
if (auto secondTuple = secondType->getAs<PackType>()) {
149+
auto sugaredFirstTuple = sugaredFirstType->getAs<PackType>();
150+
if (firstTuple->getNumElements() != secondTuple->getNumElements())
151+
return mismatch(firstTuple.getPointer(), secondTuple,
152+
sugaredFirstType);
153+
154+
for (unsigned i = 0, n = firstTuple->getNumElements(); i != n; ++i) {
155+
Type secondElt = secondTuple->getElementType(i);
156+
157+
// Recurse on the pack elements.
158+
if (!this->visit(firstTuple.getElementType(i), secondElt,
159+
sugaredFirstTuple->getElementType(i)))
160+
return false;
161+
}
162+
163+
return true;
164+
}
165+
166+
// Pack/non-pack mismatch.
167+
return mismatch(firstTuple.getPointer(), secondType, sugaredFirstType);
168+
}
146169
bool visitReferenceStorageType(CanReferenceStorageType firstStorage,
147170
Type secondType, Type sugaredFirstType) {
148171
auto _secondStorage = secondType->getCanonicalType();

include/swift/AST/TypeNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ TYPE(ProtocolComposition, Type)
165165
TYPE(Existential, Type)
166166
TYPE(LValue, Type)
167167
TYPE(InOut, Type)
168+
TYPE(Pack, Type)
168169
UNCHECKED_TYPE(TypeVariable, Type)
169170
ABSTRACT_SUGARED_TYPE(Sugar, Type)
170171
SUGARED_TYPE(Paren, SugarType)

include/swift/AST/Types.h

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6126,6 +6126,82 @@ class PlaceholderType : public TypeBase {
61266126
};
61276127
DEFINE_EMPTY_CAN_TYPE_WRAPPER(PlaceholderType, Type)
61286128

6129+
/// PackType - The type of a pack of arguments provided to a
6130+
/// \c PackExpansionType to guide the pack expansion process.
6131+
///
6132+
/// A pack type looks a lot like a tuple in the surface language, except there
6133+
/// is no way for the user to spell a pack. Pack types are created by the solver
6134+
/// when it encounters an apply of a variadic generic function, as in
6135+
///
6136+
/// \code
6137+
/// func print<T...>(_ xs: T...) {}
6138+
/// // Creates a pack type <String, Int, String>
6139+
/// print("Macs say Hello in", 42, " different languages")
6140+
/// \endcode
6141+
///
6142+
/// Pack types substituted into the variadic generic arguments of a
6143+
/// \c PackExpansionType "trip" the pack expansion and cause it to produce a
6144+
/// new pack type with the pack expansion pattern applied.
6145+
///
6146+
/// \code
6147+
/// typealias Foo<T...> = (T?...)
6148+
/// Foo<Int, String, Int> // Forces expansion to (Int?, String?, Int?)
6149+
/// \endcode
6150+
class PackType final : public TypeBase, public llvm::FoldingSetNode,
6151+
private llvm::TrailingObjects<PackType, Type> {
6152+
friend class ASTContext;
6153+
friend TrailingObjects;
6154+
6155+
public:
6156+
/// Creates a new, empty pack.
6157+
static PackType *getEmpty(const ASTContext &C);
6158+
/// Creates a pack from the types in \p elements.
6159+
static PackType *get(const ASTContext &C, ArrayRef<Type> elements);
6160+
6161+
public:
6162+
/// Retrieves the number of elements in this pack.
6163+
unsigned getNumElements() const { return Bits.PackType.Count; }
6164+
6165+
/// Retrieves the type of the elements in the pack.
6166+
ArrayRef<Type> getElementTypes() const {
6167+
return {getTrailingObjects<Type>(), getNumElements()};
6168+
}
6169+
6170+
/// Returns the type of the element at the given \p index.
6171+
Type getElementType(unsigned index) const {
6172+
return getTrailingObjects<Type>()[index];
6173+
}
6174+
6175+
public:
6176+
void Profile(llvm::FoldingSetNodeID &ID) {
6177+
Profile(ID, getElementTypes());
6178+
}
6179+
static void Profile(llvm::FoldingSetNodeID &ID, ArrayRef<Type> Elements);
6180+
6181+
// Implement isa/cast/dyncast/etc.
6182+
static bool classof(const TypeBase *T) {
6183+
return T->getKind() == TypeKind::Pack;
6184+
}
6185+
6186+
private:
6187+
PackType(ArrayRef<Type> elements, const ASTContext *CanCtx,
6188+
RecursiveTypeProperties properties)
6189+
: TypeBase(TypeKind::Pack, CanCtx, properties) {
6190+
Bits.PackType.Count = elements.size();
6191+
std::uninitialized_copy(elements.begin(), elements.end(),
6192+
getTrailingObjects<Type>());
6193+
}
6194+
};
6195+
BEGIN_CAN_TYPE_WRAPPER(PackType, Type)
6196+
CanType getElementType(unsigned elementNo) const {
6197+
return CanType(getPointer()->getElementType(elementNo));
6198+
}
6199+
6200+
CanTypeArrayRef getElementTypes() const {
6201+
return CanTypeArrayRef(getPointer()->getElementTypes());
6202+
}
6203+
END_CAN_TYPE_WRAPPER(PackType, Type)
6204+
61296205
/// getASTContext - Return the ASTContext that this type belongs to.
61306206
inline ASTContext &TypeBase::getASTContext() {
61316207
// If this type is canonical, it has the ASTContext in it.

lib/AST/ASTContext.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ struct ASTContext::Implementation {
388388
llvm::DenseMap<Type, ErrorType *> ErrorTypesWithOriginal;
389389
llvm::FoldingSet<TypeAliasType> TypeAliasTypes;
390390
llvm::FoldingSet<TupleType> TupleTypes;
391+
llvm::FoldingSet<PackType> PackTypes;
391392
llvm::DenseMap<llvm::PointerIntPair<TypeBase*, 3, unsigned>,
392393
MetatypeType*> MetatypeTypes;
393394
llvm::DenseMap<llvm::PointerIntPair<TypeBase*, 3, unsigned>,
@@ -469,6 +470,7 @@ struct ASTContext::Implementation {
469470
llvm::FoldingSet<SILBoxType> SILBoxTypes;
470471
llvm::DenseMap<BuiltinIntegerWidth, BuiltinIntegerType*> IntegerTypes;
471472
llvm::FoldingSet<BuiltinVectorType> BuiltinVectorTypes;
473+
llvm::FoldingSet<PackExpansionType> PackExpansionTypes;
472474
llvm::FoldingSet<DeclName::CompoundDeclName> CompoundNames;
473475
llvm::DenseMap<UUID, OpenedArchetypeType *> OpenedExistentialArchetypes;
474476
llvm::FoldingSet<IndexSubset> IndexSubsets;
@@ -620,6 +622,7 @@ ASTContext::ASTContext(LangOptions &langOpts, TypeCheckerOptions &typeckOpts,
620622
TheUnresolvedType(new (*this, AllocationArena::Permanent)
621623
UnresolvedType(*this)),
622624
TheEmptyTupleType(TupleType::get(ArrayRef<TupleTypeElt>(), *this)),
625+
TheEmptyPackType(PackType::get(*this, {})),
623626
TheAnyType(ProtocolCompositionType::get(*this, ArrayRef<Type>(),
624627
/*HasExplicitAnyObject=*/false)),
625628
#define SINGLETON_TYPE(SHORT_ID, ID) \
@@ -2925,6 +2928,70 @@ Type TupleTypeElt::getType() const {
29252928
return ElementType;
29262929
}
29272930

2931+
PackExpansionType *PackExpansionType::get(Type patternTy) {
2932+
assert(patternTy && "Missing pattern type in expansion");
2933+
2934+
auto &context = patternTy->getASTContext();
2935+
llvm::FoldingSetNodeID id;
2936+
PackExpansionType::Profile(id, patternTy);
2937+
2938+
void *insertPos;
2939+
if (PackExpansionType *expType =
2940+
context.getImpl().PackExpansionTypes.FindNodeOrInsertPos(id,
2941+
insertPos))
2942+
return expType;
2943+
2944+
const ASTContext *canCtx = patternTy->isCanonical() ? &context : nullptr;
2945+
PackExpansionType *expansionTy = new (context, AllocationArena::Permanent)
2946+
PackExpansionType(patternTy, canCtx);
2947+
context.getImpl().PackExpansionTypes.InsertNode(expansionTy, insertPos);
2948+
return expansionTy;
2949+
}
2950+
2951+
void PackExpansionType::Profile(llvm::FoldingSetNodeID &ID, Type patternType) {
2952+
ID.AddPointer(patternType.getPointer());
2953+
}
2954+
2955+
PackType *PackType::getEmpty(const ASTContext &C) {
2956+
return cast<PackType>(CanType(C.TheEmptyPackType));
2957+
}
2958+
2959+
PackType *PackType::get(const ASTContext &C, ArrayRef<Type> elements) {
2960+
RecursiveTypeProperties properties;
2961+
bool isCanonical = true;
2962+
for (Type eltTy : elements) {
2963+
properties |= eltTy->getRecursiveProperties();
2964+
if (!eltTy->isCanonical())
2965+
isCanonical = false;
2966+
}
2967+
2968+
auto arena = getArena(properties);
2969+
2970+
void *InsertPos = nullptr;
2971+
// Check to see if we've already seen this pack before.
2972+
llvm::FoldingSetNodeID ID;
2973+
PackType::Profile(ID, elements);
2974+
2975+
if (PackType *TT
2976+
= C.getImpl().getArena(arena).PackTypes.FindNodeOrInsertPos(ID,InsertPos))
2977+
return TT;
2978+
2979+
size_t bytes = totalSizeToAlloc<Type>(elements.size());
2980+
// TupleType will copy the fields list into ASTContext owned memory.
2981+
void *mem = C.Allocate(bytes, alignof(PackType), arena);
2982+
auto New =
2983+
new (mem) PackType(elements, isCanonical ? &C : nullptr, properties);
2984+
C.getImpl().getArena(arena).PackTypes.InsertNode(New, InsertPos);
2985+
return New;
2986+
}
2987+
2988+
void PackType::Profile(llvm::FoldingSetNodeID &ID, ArrayRef<Type> Elements) {
2989+
ID.AddInteger(Elements.size());
2990+
for (Type Ty : Elements) {
2991+
ID.AddPointer(Ty.getPointer());
2992+
}
2993+
}
2994+
29282995
Type AnyFunctionType::Param::getOldType() const {
29292996
if (Flags.isInOut()) return InOutType::get(Ty);
29302997
return Ty;

lib/AST/ASTMangler.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,12 @@ void ASTMangler::appendType(Type type, GenericSignature sig,
11691169
return appendAnyGenericType(decl);
11701170
}
11711171

1172+
case TypeKind::Pack:
1173+
assert(DWARFMangling && "sugared types are only legal for the debugger");
1174+
appendOperator("XSP");
1175+
llvm_unreachable("Unimplemented");
1176+
return;
1177+
11721178
case TypeKind::Paren:
11731179
assert(DWARFMangling && "sugared types are only legal for the debugger");
11741180
appendType(cast<ParenType>(tybase)->getUnderlyingType(), sig, forDecl);

lib/AST/ASTPrinter.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4626,6 +4626,19 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
46264626
Printer << ")";
46274627
}
46284628

4629+
void visitPackType(PackType *T) {
4630+
Printer << "(";
4631+
4632+
auto Fields = T->getElementTypes();
4633+
for (unsigned i = 0, e = Fields.size(); i != e; ++i) {
4634+
if (i)
4635+
Printer << ", ";
4636+
Type EltType = Fields[i];
4637+
visit(EltType);
4638+
}
4639+
Printer << ")";
4640+
}
4641+
46294642
void visitTupleType(TupleType *T) {
46304643
Printer.callPrintStructurePre(PrintStructureKind::TupleType);
46314644
SWIFT_DEFER { Printer.printStructurePost(PrintStructureKind::TupleType); };

lib/AST/Type.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ bool CanType::isReferenceTypeImpl(CanType type, const GenericSignatureImpl *sig,
230230
case TypeKind::BoundGenericEnum:
231231
case TypeKind::BoundGenericStruct:
232232
case TypeKind::SILToken:
233+
case TypeKind::Pack:
233234
#define REF_STORAGE(Name, ...) \
234235
case TypeKind::Name##Storage:
235236
#include "swift/AST/ReferenceStorage.def"
@@ -1343,6 +1344,21 @@ CanType TypeBase::computeCanonicalType() {
13431344
break;
13441345
}
13451346

1347+
case TypeKind::Pack: {
1348+
PackType *PT = cast<PackType>(this);
1349+
assert(PT->getNumElements() != 0 && "Empty packs are always canonical");
1350+
1351+
SmallVector<Type, 8> CanTys;
1352+
CanTys.reserve(PT->getNumElements());
1353+
for (Type field : PT->getElementTypes()) {
1354+
CanTys.push_back(field->getCanonicalType());
1355+
}
1356+
1357+
const ASTContext &C = CanTys[0]->getASTContext();
1358+
Result = PackType::get(C, CanTys)->castTo<PackType>();
1359+
break;
1360+
}
1361+
13461362
case TypeKind::Tuple: {
13471363
TupleType *TT = cast<TupleType>(this);
13481364
assert(TT->getNumElements() != 0 && "Empty tuples are always canonical");

lib/AST/TypeWalker.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ class Traversal : public TypeVisitor<Traversal, bool>
4949
}
5050
bool visitSILTokenType(SILTokenType *ty) { return false; }
5151

52+
bool visitPackType(PackType *ty) {
53+
for (auto elementTy : ty->getElementTypes())
54+
if (doIt(elementTy))
55+
return true;
56+
return false;
57+
}
58+
5259
bool visitParenType(ParenType *ty) {
5360
return doIt(ty->getUnderlyingType());
5461
}

0 commit comments

Comments
 (0)