Skip to content

Commit d95861b

Browse files
authored
Merge pull request #21967 from slavapestov/cache-inherited-protocols
AST: Cache ProtocolDecl::getInheritedProtocols()
2 parents c86351d + eef3efb commit d95861b

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
@@ -493,7 +493,7 @@ class alignas(1 << DeclAlignInBits) Decl {
493493
HasLazyConformances : 1
494494
);
495495

496-
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+2+8+16,
496+
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+2+1+8+16,
497497
/// Whether the \c RequiresClass bit is valid.
498498
RequiresClassValid : 1,
499499

@@ -519,6 +519,9 @@ class alignas(1 << DeclAlignInBits) Decl {
519519
/// The stage of the circularity check for this protocol.
520520
Circularity : 2,
521521

522+
/// Whether we've computed the inherited protocols list yet.
523+
InheritedProtocolsValid : 1,
524+
522525
: NumPadBits,
523526

524527
/// If this is a compiler-known protocol, this will be a KnownProtocolKind
@@ -3893,15 +3896,7 @@ struct SelfReferenceKind {
38933896
class ProtocolDecl final : public NominalTypeDecl {
38943897
SourceLoc ProtocolLoc;
38953898

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

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

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

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

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

lib/AST/Decl.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3909,16 +3909,19 @@ ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc,
39093909
Bits.ProtocolDecl.ExistentialConformsToSelf = false;
39103910
Bits.ProtocolDecl.Circularity
39113911
= static_cast<unsigned>(CircularityCheck::Unchecked);
3912+
Bits.ProtocolDecl.InheritedProtocolsValid = 0;
39123913
Bits.ProtocolDecl.NumRequirementsInSignature = 0;
39133914
Bits.ProtocolDecl.HasMissingRequirements = false;
39143915
Bits.ProtocolDecl.KnownProtocol = 0;
3915-
setTrailingWhereClause(TrailingWhere);
3916+
setTrailingWhereClause(TrailingWhere);
39163917
}
39173918

3918-
llvm::TinyPtrVector<ProtocolDecl *>
3919-
ProtocolDecl::getInheritedProtocols() const {
3920-
llvm::TinyPtrVector<ProtocolDecl *> result;
3921-
SmallPtrSet<const ProtocolDecl *, 4> known;
3919+
ArrayRef<ProtocolDecl *>
3920+
ProtocolDecl::getInheritedProtocolsSlow() {
3921+
Bits.ProtocolDecl.InheritedProtocolsValid = true;
3922+
3923+
llvm::SmallVector<ProtocolDecl *, 2> result;
3924+
SmallPtrSet<const ProtocolDecl *, 2> known;
39223925
known.insert(this);
39233926
bool anyObject = false;
39243927
for (const auto found :
@@ -3930,7 +3933,9 @@ ProtocolDecl::getInheritedProtocols() const {
39303933
}
39313934
}
39323935

3933-
return result;
3936+
auto &ctx = getASTContext();
3937+
InheritedProtocols = ctx.AllocateCopy(result);
3938+
return InheritedProtocols;
39343939
}
39353940

39363941
llvm::TinyPtrVector<AssociatedTypeDecl *>

lib/AST/NameLookup.cpp

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

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

@@ -623,7 +631,7 @@ SelfBoundsFromWhereClauseRequest::evaluate(
623631
// Resolve the right-hand side.
624632
DirectlyReferencedTypeDecls rhsDecls;
625633
if (auto typeRepr = req.getConstraintRepr()) {
626-
rhsDecls = directReferencesForTypeRepr(evaluator, ctx, typeRepr, dc);
634+
rhsDecls = directReferencesForTypeRepr(evaluator, ctx, typeRepr, lookupDC);
627635
} else if (Type type = req.getConstraint()) {
628636
rhsDecls = directReferencesForType(type);
629637
}
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)