Skip to content

Commit d91f3ec

Browse files
committed
[AST] Lazily expand the nested types of an ArchetypeType.
An ArchetypeType has all of the information it needs to lazily compute its set of nested types (hint: they're the associated types of all of the protocols to which it conforms). Do so only when asked about the nested types. Not that there are two levels of laziness happening here: first, we only create the (sorted) array of nested types when asked about the nested types the first time. Second, even when we do create it, we only record the names of these types---the actual archetypes (or concrete types) behind these names are lazily created when requested. Of course, all of this laziness is short-lived, because ArchetypeBuilder::getGenericEnvironment() forces all of the archetypes to be constructed.
1 parent ff80a2e commit d91f3ec

File tree

3 files changed

+85
-29
lines changed

3 files changed

+85
-29
lines changed

include/swift/AST/Types.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,10 +287,11 @@ class alignas(1 << TypeAlignInBits) TypeBase {
287287
struct ArchetypeTypeBitfields {
288288
unsigned : NumTypeBaseBits;
289289

290+
unsigned ExpandedNestedTypes : 1;
290291
unsigned HasSuperclass : 1;
291292
unsigned NumProtocols : 16;
292293
};
293-
enum { NumArchetypeTypeBitfields = NumTypeBaseBits + 17 };
294+
enum { NumArchetypeTypeBitfields = NumTypeBaseBits + 18 };
294295
static_assert(NumArchetypeTypeBitfields <= 32, "fits in an unsigned");
295296

296297
struct TypeVariableTypeBitfields {
@@ -3554,6 +3555,16 @@ class ProtocolType : public NominalType, public llvm::FoldingSetNode {
35543555
/// in the protocol list, then sorting them in some stable order.
35553556
static void canonicalizeProtocols(SmallVectorImpl<ProtocolDecl *> &protocols);
35563557

3558+
/// Visit all of the protocols in the given list of protocols, along with their
3559+
///
3560+
/// \param fn Visitor function called for each protocol (just once). If it
3561+
/// returns \c true, the visit operation will abort and return \c true.
3562+
///
3563+
/// \returns \c true if any invocation of \c fn returns \c true, and \c false
3564+
/// otherwise.
3565+
static bool visitAllProtocols(ArrayRef<ProtocolDecl *> protocols,
3566+
llvm::function_ref<bool(ProtocolDecl *)> fn);
3567+
35573568
/// Compare two protocols to provide them with a stable ordering for
35583569
/// use in sorting.
35593570
static int compareProtocols(ProtocolDecl * const* PP1,
@@ -3801,6 +3812,7 @@ class ArchetypeType final : public SubstitutableType,
38013812
llvm::PointerUnion<AssociatedTypeDecl *, Identifier> AssocTypeOrName;
38023813
MutableArrayRef<std::pair<Identifier, NestedType>> NestedTypes;
38033814

3815+
void populateNestedTypes() const;
38043816
void resolveNestedType(std::pair<Identifier, NestedType> &nested) const;
38053817

38063818
public:
@@ -3936,9 +3948,9 @@ class ArchetypeType final : public SubstitutableType,
39363948
getAllNestedTypes(bool resolveTypes = true) const;
39373949

39383950
/// \brief Set the nested types to a copy of the given array of
3939-
/// archetypes, which will first be sorted in place.
3951+
/// archetypes.
39403952
void setNestedTypes(ASTContext &Ctx,
3941-
MutableArrayRef<std::pair<Identifier, NestedType>> Nested);
3953+
ArrayRef<std::pair<Identifier, NestedType>> Nested);
39423954

39433955
/// Register a nested type with the given name.
39443956
void registerNestedType(Identifier name, NestedType nested);

lib/AST/ArchetypeBuilder.cpp

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -752,30 +752,6 @@ ArchetypeBuilder::PotentialArchetype::getTypeInContext(
752752
genericEnv->addMapping(getGenericParamKey(), arch);
753753
}
754754

755-
// Collect the set of nested types of this archetype, and put them into
756-
// the archetype itself.
757-
if (!representative->getNestedTypes().empty()) {
758-
SmallVector<std::pair<Identifier, NestedType>, 4> FlatNestedTypes;
759-
for (auto Nested : representative->getNestedTypes()) {
760-
// Skip type aliases, which are just shortcuts.
761-
if (Nested.second.front()->getTypeAliasDecl())
762-
continue;
763-
bool anyNotRenamed = false;
764-
for (auto NestedPA : Nested.second) {
765-
if (!NestedPA->wasRenamed()) {
766-
anyNotRenamed = true;
767-
break;
768-
}
769-
}
770-
771-
if (!anyNotRenamed)
772-
continue;
773-
774-
FlatNestedTypes.push_back({ Nested.first, NestedType() });
775-
}
776-
arch->setNestedTypes(ctx, FlatNestedTypes);
777-
}
778-
779755
return NestedType::forArchetype(arch);
780756
}
781757

lib/AST/Type.cpp

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,37 @@ int ProtocolType::compareProtocols(ProtocolDecl * const* PP1,
10441044
return P1->getName().str().compare(P2->getName().str());
10451045
}
10461046

1047+
bool ProtocolType::visitAllProtocols(
1048+
ArrayRef<ProtocolDecl *> protocols,
1049+
llvm::function_ref<bool(ProtocolDecl *)> fn) {
1050+
SmallVector<ProtocolDecl *, 4> stack;
1051+
SmallPtrSet<ProtocolDecl *, 4> knownProtocols;
1052+
1053+
// Prepopulate the stack.
1054+
for (auto proto : protocols) {
1055+
if (knownProtocols.insert(proto).second)
1056+
stack.push_back(proto);
1057+
}
1058+
std::reverse(stack.begin(), stack.end());
1059+
1060+
while (!stack.empty()) {
1061+
auto proto = stack.back();
1062+
stack.pop_back();
1063+
1064+
// Visit this protocol.
1065+
if (fn(proto))
1066+
return true;
1067+
1068+
// Add inherited protocols that we haven't seen already.
1069+
for (auto inherited : proto->getInheritedProtocols(nullptr)) {
1070+
if (knownProtocols.insert(inherited).second)
1071+
stack.push_back(inherited);
1072+
}
1073+
}
1074+
1075+
return false;
1076+
}
1077+
10471078
void ProtocolType::canonicalizeProtocols(
10481079
SmallVectorImpl<ProtocolDecl *> &protocols) {
10491080
llvm::SmallDenseMap<ProtocolDecl *, unsigned> known;
@@ -2494,6 +2525,7 @@ ArchetypeType::ArchetypeType(
24942525
}
24952526

24962527
// Set up the bits we need for trailing objects to work.
2528+
ArchetypeTypeBits.ExpandedNestedTypes = false;
24972529
ArchetypeTypeBits.HasSuperclass = static_cast<bool>(Superclass);
24982530
ArchetypeTypeBits.NumProtocols = ConformsTo.size();
24992531

@@ -2515,6 +2547,7 @@ ArchetypeType::ArchetypeType(const ASTContext &Ctx, Type Existential,
25152547
RecursiveTypeProperties::HasOpenedExistential)),
25162548
ParentOrOpenedOrEnvironment(Existential.getPointer()) {
25172549
// Set up the bits we need for trailing objects to work.
2550+
ArchetypeTypeBits.ExpandedNestedTypes = false;
25182551
ArchetypeTypeBits.HasSuperclass = static_cast<bool>(Superclass);
25192552
ArchetypeTypeBits.NumProtocols = ConformsTo.size();
25202553

@@ -2604,7 +2637,32 @@ namespace {
26042637
};
26052638
}
26062639

2640+
void ArchetypeType::populateNestedTypes() const {
2641+
if (ArchetypeTypeBits.ExpandedNestedTypes) return;
2642+
2643+
// Collect the set of nested types of this archetype.
2644+
SmallVector<std::pair<Identifier, NestedType>, 4> nestedTypes;
2645+
llvm::SmallPtrSet<Identifier, 4> knownNestedTypes;
2646+
ProtocolType::visitAllProtocols(getConformsTo(),
2647+
[&](ProtocolDecl *proto) -> bool {
2648+
for (auto member : proto->getMembers()) {
2649+
if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
2650+
if (knownNestedTypes.insert(assocType->getName()).second)
2651+
nestedTypes.push_back({ assocType->getName(), NestedType() });
2652+
}
2653+
}
2654+
2655+
return false;
2656+
});
2657+
2658+
// Record the nested types.
2659+
auto mutableThis = const_cast<ArchetypeType *>(this);
2660+
mutableThis->setNestedTypes(mutableThis->getASTContext(), nestedTypes);
2661+
}
2662+
26072663
ArchetypeType::NestedType ArchetypeType::getNestedType(Identifier Name) const {
2664+
populateNestedTypes();
2665+
26082666
auto Pos = std::lower_bound(NestedTypes.begin(), NestedTypes.end(), Name,
26092667
OrderArchetypeByName());
26102668
if (Pos == NestedTypes.end() || Pos->first != Name) {
@@ -2623,6 +2681,8 @@ ArchetypeType::NestedType ArchetypeType::getNestedType(Identifier Name) const {
26232681

26242682
Optional<ArchetypeType::NestedType> ArchetypeType::getNestedTypeIfKnown(
26252683
Identifier Name) const {
2684+
populateNestedTypes();
2685+
26262686
auto Pos = std::lower_bound(NestedTypes.begin(), NestedTypes.end(), Name,
26272687
OrderArchetypeByName());
26282688
if (Pos == NestedTypes.end() || Pos->first != Name || !Pos->second)
@@ -2632,13 +2692,17 @@ Optional<ArchetypeType::NestedType> ArchetypeType::getNestedTypeIfKnown(
26322692
}
26332693

26342694
bool ArchetypeType::hasNestedType(Identifier Name) const {
2695+
populateNestedTypes();
2696+
26352697
auto Pos = std::lower_bound(NestedTypes.begin(), NestedTypes.end(), Name,
26362698
OrderArchetypeByName());
26372699
return Pos != NestedTypes.end() && Pos->first == Name;
26382700
}
26392701

26402702
ArrayRef<std::pair<Identifier, ArchetypeType::NestedType>>
26412703
ArchetypeType::getAllNestedTypes(bool resolveTypes) const {
2704+
populateNestedTypes();
2705+
26422706
if (resolveTypes) {
26432707
for (auto &nested : NestedTypes) {
26442708
if (!nested.second)
@@ -2651,12 +2715,16 @@ ArchetypeType::getAllNestedTypes(bool resolveTypes) const {
26512715

26522716
void ArchetypeType::setNestedTypes(
26532717
ASTContext &Ctx,
2654-
MutableArrayRef<std::pair<Identifier, NestedType>> Nested) {
2655-
std::sort(Nested.begin(), Nested.end(), OrderArchetypeByName());
2718+
ArrayRef<std::pair<Identifier, NestedType>> Nested) {
2719+
assert(!ArchetypeTypeBits.ExpandedNestedTypes && "Already expanded");
26562720
NestedTypes = Ctx.AllocateCopy(Nested);
2721+
std::sort(NestedTypes.begin(), NestedTypes.end(), OrderArchetypeByName());
2722+
ArchetypeTypeBits.ExpandedNestedTypes = true;
26572723
}
26582724

26592725
void ArchetypeType::registerNestedType(Identifier name, NestedType nested) {
2726+
populateNestedTypes();
2727+
26602728
auto found = std::lower_bound(NestedTypes.begin(), NestedTypes.end(), name,
26612729
OrderArchetypeByName());
26622730
assert(found != NestedTypes.end() && found->first == name &&

0 commit comments

Comments
 (0)