Skip to content

Commit b947a47

Browse files
committed
[AST] Reimplement ProtocolDecl::getInheritedProtocols() on decl name lookup.
Use the declaration-based name lookup facilities to re-implement ProtocolDecl::getInheritedProtocols(), rather than dynamically selecting between the requirement signature and the inherited types. This reduces dependencies for this computation down to basic name lookup (no semantic analysis) and gives us a stable result.
1 parent 6556926 commit b947a47

File tree

5 files changed

+44
-53
lines changed

5 files changed

+44
-53
lines changed

lib/AST/Decl.cpp

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3539,41 +3539,20 @@ ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc,
35393539
llvm::TinyPtrVector<ProtocolDecl *>
35403540
ProtocolDecl::getInheritedProtocols() const {
35413541
llvm::TinyPtrVector<ProtocolDecl *> result;
3542-
3543-
// FIXME: Gather inherited protocols from the "inherited" list.
3544-
// We shouldn't need this, but it shows up in recursive invocations.
3545-
if (!isRequirementSignatureComputed()) {
3546-
SmallPtrSet<ProtocolDecl *, 4> known;
3547-
if (Bits.ProtocolDecl.ComputingInheritedProtocols) return result;
3548-
3549-
auto *self = const_cast<ProtocolDecl *>(this);
3550-
self->Bits.ProtocolDecl.ComputingInheritedProtocols = true;
3551-
for (unsigned index : indices(getInherited())) {
3552-
if (auto type = getInheritedType(index)) {
3553-
// Only protocols can appear in the inheritance clause
3554-
// of a protocol -- anything else should get diagnosed
3555-
// elsewhere.
3556-
if (type->isExistentialType()) {
3557-
auto layout = type->getExistentialLayout();
3558-
for (auto protoTy : layout.getProtocols()) {
3559-
auto *protoDecl = protoTy->getDecl();
3560-
if (known.insert(protoDecl).second)
3561-
result.push_back(protoDecl);
3562-
}
3563-
}
3564-
}
3542+
SmallPtrSet<const ProtocolDecl *, 4> known;
3543+
known.insert(this);
3544+
bool anyObject = false;
3545+
for (const auto &found :
3546+
getDirectlyInheritedNominalTypeDecls(
3547+
const_cast<ProtocolDecl *>(this), anyObject)) {
3548+
if (auto proto = dyn_cast<ProtocolDecl>(found.second)) {
3549+
if (known.insert(proto).second)
3550+
result.push_back(proto);
35653551
}
3566-
self->Bits.ProtocolDecl.ComputingInheritedProtocols = false;
3567-
return result;
35683552
}
35693553

3570-
// Gather inherited protocols from the requirement signature.
3571-
auto selfType = getProtocolSelfType();
3572-
for (const auto &req : getRequirementSignature()) {
3573-
if (req.getKind() == RequirementKind::Conformance &&
3574-
req.getFirstType()->isEqual(selfType))
3575-
result.push_back(req.getSecondType()->castTo<ProtocolType>()->getDecl());
3576-
}
3554+
// FIXME: ComputingInheritedProtocols is dynamically dead.
3555+
35773556
return result;
35783557
}
35793558

@@ -3644,10 +3623,13 @@ bool ProtocolDecl::walkInheritedProtocols(
36443623
bool ProtocolDecl::inheritsFrom(const ProtocolDecl *super) const {
36453624
if (this == super)
36463625
return false;
3647-
3648-
auto allProtocols = getLocalProtocols();
3649-
return std::find(allProtocols.begin(), allProtocols.end(), super)
3650-
!= allProtocols.end();
3626+
3627+
return walkInheritedProtocols([super](ProtocolDecl *inherited) {
3628+
if (inherited == super)
3629+
return TypeWalker::Action::Stop;
3630+
3631+
return TypeWalker::Action::Continue;
3632+
});
36513633
}
36523634

36533635
bool ProtocolDecl::requiresClassSlow() {

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3016,6 +3016,11 @@ void ArchetypeType::resolveNestedType(
30163016
builder.resolveEquivalenceClass(
30173017
memberInterfaceType,
30183018
ArchetypeResolutionKind::CompleteWellFormed);
3019+
if (!equivClass) {
3020+
nested.second = ErrorType::get(interfaceType);
3021+
return;
3022+
}
3023+
30193024
auto result = equivClass->getTypeInContext(builder, genericEnv);
30203025
assert(!nested.second ||
30213026
nested.second->isEqual(result) ||

lib/AST/Module.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -592,10 +592,6 @@ ModuleDecl::lookupConformance(Type type, ProtocolDecl *protocol) {
592592
// existential's list of conformances and the existential conforms to
593593
// itself.
594594
if (type->isExistentialType()) {
595-
// FIXME: Recursion break.
596-
if (!protocol->hasValidSignature())
597-
return None;
598-
599595
// If the existential type cannot be represented or the protocol does not
600596
// conform to itself, there's no point in looking further.
601597
if (!protocol->existentialConformsToSelf())

lib/AST/NameLookup.cpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1801,26 +1801,34 @@ bool DeclContext::lookupQualified(ArrayRef<NominalTypeDecl *> typeDecls,
18011801
if (!wantProtocolMembers && !currentIsProtocol)
18021802
continue;
18031803

1804-
if (!sawClassDecl) {
1805-
if (auto *protoDecl = dyn_cast<ProtocolDecl>(current)) {
1804+
SmallVector<ProtocolDecl *, 4> protocols;
1805+
1806+
if (auto *protoDecl = dyn_cast<ProtocolDecl>(current)) {
1807+
// If we haven't seen a class declaration yet, look into the protocol.
1808+
if (!sawClassDecl) {
18061809
if (auto superclassDecl = protoDecl->getSuperclassDecl()) {
18071810
visited.insert(superclassDecl);
18081811
stack.push_back(superclassDecl);
18091812
}
18101813
}
1811-
}
18121814

1813-
SmallVector<ProtocolDecl *, 4> protocols;
1814-
for (auto proto : current->getAllProtocols()) {
1815-
if (visited.insert(proto).second) {
1816-
stack.push_back(proto);
1815+
// Collect inherited protocols.
1816+
for (auto inheritedProto : protoDecl->getInheritedProtocols()) {
1817+
addNominalType(inheritedProto);
1818+
}
1819+
} else {
1820+
// Collect the protocols to which the nominal type conforms.
1821+
for (auto proto : current->getAllProtocols()) {
1822+
if (visited.insert(proto).second) {
1823+
stack.push_back(proto);
1824+
}
18171825
}
1818-
}
18191826

1820-
// For a class, we don't need to visit the protocol members of the
1821-
// superclass: that's already handled.
1822-
if (isa<ClassDecl>(current))
1823-
wantProtocolMembers = false;
1827+
// For a class, we don't need to visit the protocol members of the
1828+
// superclass: that's already handled.
1829+
if (isa<ClassDecl>(current))
1830+
wantProtocolMembers = false;
1831+
}
18241832
}
18251833

18261834
return finishLookup(this, options, decls);

test/decl/protocol/special/JSExport.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Foundation
99

1010
@objc protocol RootJSExport : JSExport { }
1111

12-
// CHECK: @_PROTOCOL_PROTOCOLS__TtP8JSExport4Sub1_ = private constant{{.*}}_PROTOCOL__TtP8JSExport12RootJSExport_{{.*}}_PROTOCOL__TtP8JSExport8JSExport_
12+
// CHECK: @_PROTOCOL_PROTOCOLS__TtP8JSExport4Sub1_ = private constant{{.*}}_PROTOCOL__TtP8JSExport8JSExport_{{.*}}_PROTOCOL__TtP8JSExport12RootJSExport_
1313
@objc protocol Sub1 : JSExport, RootJSExport { }
1414

1515
// CHECK: @_PROTOCOL_PROTOCOLS__TtP8JSExport4Sub2_{{.*}}_PROTOCOL__TtP8JSExport4Sub1_{{.*}}_PROTOCOL__TtP8JSExport8JSExport_

0 commit comments

Comments
 (0)