mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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.
This commit is contained in:
@@ -3689,10 +3689,11 @@ private:
|
||||
static ProtocolCompositionType *build(const ASTContext &C,
|
||||
ArrayRef<Type> Protocols);
|
||||
|
||||
ProtocolCompositionType(const ASTContext *Ctx, ArrayRef<Type> Protocols)
|
||||
: TypeBase(TypeKind::ProtocolComposition, /*Context=*/Ctx,
|
||||
RecursiveTypeProperties()),
|
||||
Protocols(Protocols) { }
|
||||
ProtocolCompositionType(const ASTContext *ctx, ArrayRef<Type> protocols,
|
||||
RecursiveTypeProperties properties)
|
||||
: TypeBase(TypeKind::ProtocolComposition, /*Context=*/ctx,
|
||||
properties),
|
||||
Protocols(protocols) { }
|
||||
};
|
||||
BEGIN_CAN_TYPE_WRAPPER(ProtocolCompositionType, Type)
|
||||
/// In the canonical representation, these are all ProtocolTypes.
|
||||
|
||||
@@ -270,6 +270,7 @@ struct ASTContext::Implementation {
|
||||
llvm::FoldingSet<UnboundGenericType> UnboundGenericTypes;
|
||||
llvm::FoldingSet<BoundGenericType> BoundGenericTypes;
|
||||
llvm::FoldingSet<ProtocolType> ProtocolTypes;
|
||||
llvm::FoldingSet<ProtocolCompositionType> ProtocolCompositionTypes;
|
||||
llvm::FoldingSet<LayoutConstraintInfo> LayoutConstraints;
|
||||
|
||||
/// The set of normal protocol conformances.
|
||||
@@ -312,7 +313,6 @@ struct ASTContext::Implementation {
|
||||
llvm::DenseMap<CanType, SILBlockStorageType *> SILBlockStorageTypes;
|
||||
llvm::FoldingSet<SILBoxType> SILBoxTypes;
|
||||
llvm::DenseMap<BuiltinIntegerWidth, BuiltinIntegerType*> IntegerTypes;
|
||||
llvm::FoldingSet<ProtocolCompositionType> ProtocolCompositionTypes;
|
||||
llvm::FoldingSet<BuiltinVectorType> BuiltinVectorTypes;
|
||||
llvm::FoldingSet<GenericSignature> GenericSignatures;
|
||||
llvm::FoldingSet<DeclName::CompoundDeclName> CompoundNames;
|
||||
@@ -2798,23 +2798,31 @@ ProtocolCompositionType::build(const ASTContext &C, ArrayRef<Type> Protocols) {
|
||||
void *InsertPos = nullptr;
|
||||
llvm::FoldingSetNodeID ID;
|
||||
ProtocolCompositionType::Profile(ID, Protocols);
|
||||
if (ProtocolCompositionType *Result
|
||||
= C.Impl.ProtocolCompositionTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return Result;
|
||||
|
||||
bool isCanonical = true;
|
||||
RecursiveTypeProperties properties;
|
||||
for (Type t : Protocols) {
|
||||
if (!t->isCanonical())
|
||||
isCanonical = false;
|
||||
properties |= t->getRecursiveProperties();
|
||||
}
|
||||
|
||||
// Create a new protocol composition type.
|
||||
ProtocolCompositionType *New
|
||||
= new (C, AllocationArena::Permanent)
|
||||
auto arena = getArena(properties);
|
||||
|
||||
if (auto compTy
|
||||
= C.Impl.getArena(arena).ProtocolCompositionTypes
|
||||
.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return compTy;
|
||||
|
||||
auto compTy
|
||||
= new (C, arena)
|
||||
ProtocolCompositionType(isCanonical ? &C : nullptr,
|
||||
C.AllocateCopy(Protocols));
|
||||
C.Impl.ProtocolCompositionTypes.InsertNode(New, InsertPos);
|
||||
return New;
|
||||
C.AllocateCopy(Protocols),
|
||||
properties);
|
||||
C.Impl.getArena(arena).ProtocolCompositionTypes
|
||||
.InsertNode(compTy, InsertPos);
|
||||
return compTy;
|
||||
}
|
||||
|
||||
ReferenceStorageType *ReferenceStorageType::get(Type T, Ownership ownership,
|
||||
|
||||
@@ -894,13 +894,24 @@ Type TypeBase::getRValueInstanceType() {
|
||||
|
||||
/// \brief Collect the protocols in the existential type T into the given
|
||||
/// vector.
|
||||
static void addProtocols(Type T, SmallVectorImpl<ProtocolDecl *> &Protocols) {
|
||||
static void addProtocols(Type T, SmallVectorImpl<ProtocolDecl *> &Protocols,
|
||||
Type &Superclass) {
|
||||
if (auto Proto = T->getAs<ProtocolType>()) {
|
||||
Protocols.push_back(Proto->getDecl());
|
||||
} else if (auto PC = T->getAs<ProtocolCompositionType>()) {
|
||||
for (auto P : PC->getProtocols())
|
||||
addProtocols(P, Protocols);
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto PC = T->getAs<ProtocolCompositionType>()) {
|
||||
for (auto P : PC->getProtocols())
|
||||
addProtocols(P, Protocols, Superclass);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(isa<ClassDecl>(T->getAnyNominal()) && "Non-class, non-protocol "
|
||||
"member in protocol composition");
|
||||
assert((!Superclass || Superclass->isEqual(T)) &&
|
||||
"Should have diagnosed multiple superclasses by now");
|
||||
Superclass = T;
|
||||
}
|
||||
|
||||
/// \brief Add the protocol (or protocols) in the type T to the stack of
|
||||
@@ -2751,33 +2762,37 @@ bool ProtocolCompositionType::requiresClass() const {
|
||||
}
|
||||
|
||||
Type ProtocolCompositionType::get(const ASTContext &C,
|
||||
ArrayRef<Type> ProtocolTypes) {
|
||||
for (Type t : ProtocolTypes) {
|
||||
ArrayRef<Type> MemberTypes) {
|
||||
for (Type t : MemberTypes) {
|
||||
if (!t->isCanonical())
|
||||
return build(C, ProtocolTypes);
|
||||
return build(C, MemberTypes);
|
||||
}
|
||||
|
||||
Type Superclass;
|
||||
SmallVector<ProtocolDecl *, 4> Protocols;
|
||||
for (Type t : ProtocolTypes)
|
||||
addProtocols(t, Protocols);
|
||||
for (Type t : MemberTypes) {
|
||||
addProtocols(t, Protocols, Superclass);
|
||||
}
|
||||
|
||||
// Minimize the set of protocols composed together.
|
||||
ProtocolType::canonicalizeProtocols(Protocols);
|
||||
|
||||
// If one protocol remains, its nominal type is the canonical type.
|
||||
if (Protocols.size() == 1)
|
||||
if (Protocols.size() == 1 && !Superclass)
|
||||
return Protocols.front()->getDeclaredType();
|
||||
|
||||
// Form the set of canonical protocol types from the protocol
|
||||
// declarations, and use that to build the canonical composition type.
|
||||
SmallVector<Type, 4> CanProtocolTypes;
|
||||
SmallVector<Type, 4> CanTypes;
|
||||
if (Superclass)
|
||||
CanTypes.push_back(Superclass->getCanonicalType());
|
||||
std::transform(Protocols.begin(), Protocols.end(),
|
||||
std::back_inserter(CanProtocolTypes),
|
||||
std::back_inserter(CanTypes),
|
||||
[](ProtocolDecl *Proto) {
|
||||
return Proto->getDeclaredType();
|
||||
});
|
||||
|
||||
return build(C, CanProtocolTypes);
|
||||
return build(C, CanTypes);
|
||||
}
|
||||
|
||||
FunctionType *
|
||||
|
||||
Reference in New Issue
Block a user