Skip to content

Commit 62cc67a

Browse files
authored
Merge pull request #21971 from slavapestov/cache-inherited-protocols-5.0
AST: Cache ProtocolDecl::getInheritedProtocols() [5.0]
2 parents d5bbeed + 2460aa7 commit 62cc67a

File tree

4 files changed

+55
-18
lines changed

4 files changed

+55
-18
lines changed

include/swift/AST/Decl.h

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ class alignas(1 << DeclAlignInBits) Decl {
488488
HasLazyConformances : 1
489489
);
490490

491-
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+2+8+16,
491+
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+2+1+8+16,
492492
/// Whether the \c RequiresClass bit is valid.
493493
RequiresClassValid : 1,
494494

@@ -514,6 +514,9 @@ class alignas(1 << DeclAlignInBits) Decl {
514514
/// The stage of the circularity check for this protocol.
515515
Circularity : 2,
516516

517+
/// Whether we've computed the inherited protocols list yet.
518+
InheritedProtocolsValid : 1,
519+
517520
: NumPadBits,
518521

519522
/// If this is a compiler-known protocol, this will be a KnownProtocolKind
@@ -3892,15 +3895,7 @@ struct SelfReferenceKind {
38923895
class ProtocolDecl final : public NominalTypeDecl {
38933896
SourceLoc ProtocolLoc;
38943897

3895-
/// The generic signature representing exactly the new requirements introduced
3896-
/// by this protocol.
3897-
const Requirement *RequirementSignature = nullptr;
3898-
3899-
bool requiresClassSlow();
3900-
3901-
bool existentialConformsToSelfSlow();
3902-
3903-
bool existentialTypeSupportedSlow(LazyResolver *resolver);
3898+
ArrayRef<ProtocolDecl *> InheritedProtocols;
39043899

39053900
struct {
39063901
/// The superclass decl and a bit to indicate whether the
@@ -3912,6 +3907,18 @@ class ProtocolDecl final : public NominalTypeDecl {
39123907
llvm::PointerIntPair<Type, 1, bool> SuperclassType;
39133908
} LazySemanticInfo;
39143909

3910+
/// The generic signature representing exactly the new requirements introduced
3911+
/// by this protocol.
3912+
const Requirement *RequirementSignature = nullptr;
3913+
3914+
bool requiresClassSlow();
3915+
3916+
bool existentialConformsToSelfSlow();
3917+
3918+
bool existentialTypeSupportedSlow(LazyResolver *resolver);
3919+
3920+
ArrayRef<ProtocolDecl *> getInheritedProtocolsSlow();
3921+
39153922
friend class SuperclassDeclRequest;
39163923
friend class SuperclassTypeRequest;
39173924
friend class TypeChecker;
@@ -3924,7 +3931,12 @@ class ProtocolDecl final : public NominalTypeDecl {
39243931
using Decl::getASTContext;
39253932

39263933
/// Retrieve the set of protocols inherited from this protocol.
3927-
llvm::TinyPtrVector<ProtocolDecl *> getInheritedProtocols() const;
3934+
ArrayRef<ProtocolDecl *> getInheritedProtocols() const {
3935+
if (Bits.ProtocolDecl.InheritedProtocolsValid)
3936+
return InheritedProtocols;
3937+
3938+
return const_cast<ProtocolDecl *>(this)->getInheritedProtocolsSlow();
3939+
}
39283940

39293941
/// Determine whether this protocol has a superclass.
39303942
bool hasSuperclass() const { return (bool)getSuperclassDecl(); }

lib/AST/Decl.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3856,16 +3856,19 @@ ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc,
38563856
Bits.ProtocolDecl.ExistentialConformsToSelf = false;
38573857
Bits.ProtocolDecl.Circularity
38583858
= static_cast<unsigned>(CircularityCheck::Unchecked);
3859+
Bits.ProtocolDecl.InheritedProtocolsValid = 0;
38593860
Bits.ProtocolDecl.NumRequirementsInSignature = 0;
38603861
Bits.ProtocolDecl.HasMissingRequirements = false;
38613862
Bits.ProtocolDecl.KnownProtocol = 0;
3862-
setTrailingWhereClause(TrailingWhere);
3863+
setTrailingWhereClause(TrailingWhere);
38633864
}
38643865

3865-
llvm::TinyPtrVector<ProtocolDecl *>
3866-
ProtocolDecl::getInheritedProtocols() const {
3867-
llvm::TinyPtrVector<ProtocolDecl *> result;
3868-
SmallPtrSet<const ProtocolDecl *, 4> known;
3866+
ArrayRef<ProtocolDecl *>
3867+
ProtocolDecl::getInheritedProtocolsSlow() {
3868+
Bits.ProtocolDecl.InheritedProtocolsValid = true;
3869+
3870+
llvm::SmallVector<ProtocolDecl *, 2> result;
3871+
SmallPtrSet<const ProtocolDecl *, 2> known;
38693872
known.insert(this);
38703873
bool anyObject = false;
38713874
for (const auto found :
@@ -3877,7 +3880,9 @@ ProtocolDecl::getInheritedProtocols() const {
38773880
}
38783881
}
38793882

3880-
return result;
3883+
auto &ctx = getASTContext();
3884+
InheritedProtocols = ctx.AllocateCopy(result);
3885+
return InheritedProtocols;
38813886
}
38823887

38833888
llvm::TinyPtrVector<AssociatedTypeDecl *>

lib/AST/NameLookup.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,14 @@ SelfBoundsFromWhereClauseRequest::evaluate(
590590
auto *extDecl = decl.dyn_cast<ExtensionDecl *>();
591591

592592
DeclContext *dc = protoDecl ? (DeclContext *)protoDecl : (DeclContext *)extDecl;
593+
594+
// A protocol or extension 'where' clause can reference associated types of
595+
// the protocol itself, so we have to start unqualified lookup from 'dc'.
596+
//
597+
// However, the right hand side of a 'Self' conformance constraint must be
598+
// resolved before unqualified lookup into 'dc' can work, so we make an
599+
// exception here and begin lookup from the parent context instead.
600+
auto *lookupDC = dc->getParent();
593601
auto requirements = protoDecl ? protoDecl->getTrailingWhereClause()
594602
: extDecl->getTrailingWhereClause();
595603

@@ -619,7 +627,7 @@ SelfBoundsFromWhereClauseRequest::evaluate(
619627
// Resolve the right-hand side.
620628
DirectlyReferencedTypeDecls rhsDecls;
621629
if (auto typeRepr = req.getConstraintRepr()) {
622-
rhsDecls = directReferencesForTypeRepr(evaluator, ctx, typeRepr, dc);
630+
rhsDecls = directReferencesForTypeRepr(evaluator, ctx, typeRepr, lookupDC);
623631
} else if (Type type = req.getConstraint()) {
624632
rhsDecls = directReferencesForType(type);
625633
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %target-typecheck-verify-swift -debug-cycles 2>&1 | %FileCheck --allow-empty %s
2+
3+
// Verify that protocol where clause lookups don't cause cyclic dependencies.
4+
5+
// expected-no-diagnostics
6+
7+
class C { }
8+
protocol Q { }
9+
protocol P where Self : Q, Self : C { }
10+
11+
// CHECK-NOT: CYCLE DETECTED
12+

0 commit comments

Comments
 (0)