Skip to content

Commit 32a7505

Browse files
committed
AST: Update ProtocolCompositionType::get() for subclass existentials
Don't assume all members are existential types; we could have a class (or a class-constrained existential) also, and this needs to be handled. When building a canonical protocol composition, the subclass requirement always comes first in the list of types. This is an important invariant allowing ExistentialLayout to be calculated quickly. Also, calculate the recursive properties of the composition type from the recursive properties of its members, since they're no longer trivial if the composition contains a class member with generic parameters.
1 parent d7c1d81 commit 32a7505

File tree

3 files changed

+49
-25
lines changed

3 files changed

+49
-25
lines changed

include/swift/AST/Types.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3689,10 +3689,11 @@ class ProtocolCompositionType : public TypeBase, public llvm::FoldingSetNode {
36893689
static ProtocolCompositionType *build(const ASTContext &C,
36903690
ArrayRef<Type> Protocols);
36913691

3692-
ProtocolCompositionType(const ASTContext *Ctx, ArrayRef<Type> Protocols)
3693-
: TypeBase(TypeKind::ProtocolComposition, /*Context=*/Ctx,
3694-
RecursiveTypeProperties()),
3695-
Protocols(Protocols) { }
3692+
ProtocolCompositionType(const ASTContext *ctx, ArrayRef<Type> protocols,
3693+
RecursiveTypeProperties properties)
3694+
: TypeBase(TypeKind::ProtocolComposition, /*Context=*/ctx,
3695+
properties),
3696+
Protocols(protocols) { }
36963697
};
36973698
BEGIN_CAN_TYPE_WRAPPER(ProtocolCompositionType, Type)
36983699
/// In the canonical representation, these are all ProtocolTypes.

lib/AST/ASTContext.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ struct ASTContext::Implementation {
270270
llvm::FoldingSet<UnboundGenericType> UnboundGenericTypes;
271271
llvm::FoldingSet<BoundGenericType> BoundGenericTypes;
272272
llvm::FoldingSet<ProtocolType> ProtocolTypes;
273+
llvm::FoldingSet<ProtocolCompositionType> ProtocolCompositionTypes;
273274
llvm::FoldingSet<LayoutConstraintInfo> LayoutConstraints;
274275

275276
/// The set of normal protocol conformances.
@@ -312,7 +313,6 @@ struct ASTContext::Implementation {
312313
llvm::DenseMap<CanType, SILBlockStorageType *> SILBlockStorageTypes;
313314
llvm::FoldingSet<SILBoxType> SILBoxTypes;
314315
llvm::DenseMap<BuiltinIntegerWidth, BuiltinIntegerType*> IntegerTypes;
315-
llvm::FoldingSet<ProtocolCompositionType> ProtocolCompositionTypes;
316316
llvm::FoldingSet<BuiltinVectorType> BuiltinVectorTypes;
317317
llvm::FoldingSet<GenericSignature> GenericSignatures;
318318
llvm::FoldingSet<DeclName::CompoundDeclName> CompoundNames;
@@ -2798,23 +2798,31 @@ ProtocolCompositionType::build(const ASTContext &C, ArrayRef<Type> Protocols) {
27982798
void *InsertPos = nullptr;
27992799
llvm::FoldingSetNodeID ID;
28002800
ProtocolCompositionType::Profile(ID, Protocols);
2801-
if (ProtocolCompositionType *Result
2802-
= C.Impl.ProtocolCompositionTypes.FindNodeOrInsertPos(ID, InsertPos))
2803-
return Result;
28042801

28052802
bool isCanonical = true;
2803+
RecursiveTypeProperties properties;
28062804
for (Type t : Protocols) {
28072805
if (!t->isCanonical())
28082806
isCanonical = false;
2807+
properties |= t->getRecursiveProperties();
28092808
}
28102809

28112810
// Create a new protocol composition type.
2812-
ProtocolCompositionType *New
2813-
= new (C, AllocationArena::Permanent)
2811+
auto arena = getArena(properties);
2812+
2813+
if (auto compTy
2814+
= C.Impl.getArena(arena).ProtocolCompositionTypes
2815+
.FindNodeOrInsertPos(ID, InsertPos))
2816+
return compTy;
2817+
2818+
auto compTy
2819+
= new (C, arena)
28142820
ProtocolCompositionType(isCanonical ? &C : nullptr,
2815-
C.AllocateCopy(Protocols));
2816-
C.Impl.ProtocolCompositionTypes.InsertNode(New, InsertPos);
2817-
return New;
2821+
C.AllocateCopy(Protocols),
2822+
properties);
2823+
C.Impl.getArena(arena).ProtocolCompositionTypes
2824+
.InsertNode(compTy, InsertPos);
2825+
return compTy;
28182826
}
28192827

28202828
ReferenceStorageType *ReferenceStorageType::get(Type T, Ownership ownership,

lib/AST/Type.cpp

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -894,13 +894,24 @@ Type TypeBase::getRValueInstanceType() {
894894

895895
/// \brief Collect the protocols in the existential type T into the given
896896
/// vector.
897-
static void addProtocols(Type T, SmallVectorImpl<ProtocolDecl *> &Protocols) {
897+
static void addProtocols(Type T, SmallVectorImpl<ProtocolDecl *> &Protocols,
898+
Type &Superclass) {
898899
if (auto Proto = T->getAs<ProtocolType>()) {
899900
Protocols.push_back(Proto->getDecl());
900-
} else if (auto PC = T->getAs<ProtocolCompositionType>()) {
901+
return;
902+
}
903+
904+
if (auto PC = T->getAs<ProtocolCompositionType>()) {
901905
for (auto P : PC->getProtocols())
902-
addProtocols(P, Protocols);
906+
addProtocols(P, Protocols, Superclass);
907+
return;
903908
}
909+
910+
assert(isa<ClassDecl>(T->getAnyNominal()) && "Non-class, non-protocol "
911+
"member in protocol composition");
912+
assert((!Superclass || Superclass->isEqual(T)) &&
913+
"Should have diagnosed multiple superclasses by now");
914+
Superclass = T;
904915
}
905916

906917
/// \brief Add the protocol (or protocols) in the type T to the stack of
@@ -2751,33 +2762,37 @@ bool ProtocolCompositionType::requiresClass() const {
27512762
}
27522763

27532764
Type ProtocolCompositionType::get(const ASTContext &C,
2754-
ArrayRef<Type> ProtocolTypes) {
2755-
for (Type t : ProtocolTypes) {
2765+
ArrayRef<Type> MemberTypes) {
2766+
for (Type t : MemberTypes) {
27562767
if (!t->isCanonical())
2757-
return build(C, ProtocolTypes);
2768+
return build(C, MemberTypes);
27582769
}
27592770

2771+
Type Superclass;
27602772
SmallVector<ProtocolDecl *, 4> Protocols;
2761-
for (Type t : ProtocolTypes)
2762-
addProtocols(t, Protocols);
2773+
for (Type t : MemberTypes) {
2774+
addProtocols(t, Protocols, Superclass);
2775+
}
27632776

27642777
// Minimize the set of protocols composed together.
27652778
ProtocolType::canonicalizeProtocols(Protocols);
27662779

27672780
// If one protocol remains, its nominal type is the canonical type.
2768-
if (Protocols.size() == 1)
2781+
if (Protocols.size() == 1 && !Superclass)
27692782
return Protocols.front()->getDeclaredType();
27702783

27712784
// Form the set of canonical protocol types from the protocol
27722785
// declarations, and use that to build the canonical composition type.
2773-
SmallVector<Type, 4> CanProtocolTypes;
2786+
SmallVector<Type, 4> CanTypes;
2787+
if (Superclass)
2788+
CanTypes.push_back(Superclass->getCanonicalType());
27742789
std::transform(Protocols.begin(), Protocols.end(),
2775-
std::back_inserter(CanProtocolTypes),
2790+
std::back_inserter(CanTypes),
27762791
[](ProtocolDecl *Proto) {
27772792
return Proto->getDeclaredType();
27782793
});
27792794

2780-
return build(C, CanProtocolTypes);
2795+
return build(C, CanTypes);
27812796
}
27822797

27832798
FunctionType *

0 commit comments

Comments
 (0)