Skip to content

Commit 8f36061

Browse files
authored
Merge pull request #18530 from DougGregor/protocol-decl-based-resolution
[Name lookup] Use decl-based name lookup for protocol-related queries
2 parents 8d1d873 + 7d3dd49 commit 8f36061

File tree

12 files changed

+227
-133
lines changed

12 files changed

+227
-133
lines changed

include/swift/AST/NameLookup.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,29 @@ void lookupInModule(ModuleDecl *module, ModuleDecl::AccessPathTy accessPath,
351351
ArrayRef<ModuleDecl::ImportedModule> extraImports = {});
352352

353353
} // end namespace namelookup
354+
355+
/// Retrieve the set of nominal type declarations that are directly
356+
/// "inherited" by the given declaration at a particular position in the
357+
/// list of "inherited" types.
358+
///
359+
/// Add anything we find to the \c result vector. If we come across the
360+
/// AnyObject type, set \c anyObject true.
361+
void getDirectlyInheritedNominalTypeDecls(
362+
llvm::PointerUnion<TypeDecl *, ExtensionDecl *> decl,
363+
unsigned i,
364+
llvm::SmallVectorImpl<std::pair<SourceLoc, NominalTypeDecl *>> &result,
365+
bool &anyObject);
366+
367+
/// Retrieve the set of nominal type declarations that are directly
368+
/// "inherited" by the given declaration, looking through typealiases
369+
/// and splitting out the components of compositions.
370+
///
371+
/// If we come across the AnyObject type, set \c anyObject true.
372+
SmallVector<std::pair<SourceLoc, NominalTypeDecl *>, 4>
373+
getDirectlyInheritedNominalTypeDecls(
374+
llvm::PointerUnion<TypeDecl *, ExtensionDecl *> decl,
375+
bool &anyObject);
376+
354377
} // end namespace swift
355378

356379
#endif

lib/AST/ConformanceLookupTable.cpp

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/ExistentialLayout.h"
2121
#include "swift/AST/LazyResolver.h"
2222
#include "swift/AST/Module.h"
23+
#include "swift/AST/NameLookup.h"
2324
#include "swift/AST/ProtocolConformance.h"
2425
#include "swift/AST/ProtocolConformanceRef.h"
2526
#include "llvm/Support/SaveAndRestore.h"
@@ -488,22 +489,12 @@ bool ConformanceLookupTable::addProtocol(ProtocolDecl *protocol, SourceLoc loc,
488489
void ConformanceLookupTable::addInheritedProtocols(
489490
llvm::PointerUnion<TypeDecl *, ExtensionDecl *> decl,
490491
ConformanceSource source) {
491-
// Visit each of the types in the inheritance list to find
492-
// protocols.
493-
auto typeDecl = decl.dyn_cast<TypeDecl *>();
494-
auto extDecl = decl.dyn_cast<ExtensionDecl *>();
495-
unsigned numInherited = typeDecl ? typeDecl->getInherited().size()
496-
: extDecl->getInherited().size();
497-
for (auto index : range(numInherited)) {
498-
Type inheritedType = typeDecl ? typeDecl->getInheritedType(index)
499-
: extDecl->getInheritedType(index);
500-
if (!inheritedType || !inheritedType->isExistentialType())
501-
continue;
502-
SourceLoc loc = typeDecl ? typeDecl->getInherited()[index].getLoc()
503-
: extDecl->getInherited()[index].getLoc();
504-
auto layout = inheritedType->getExistentialLayout();
505-
for (auto *proto : layout.getProtocols())
506-
addProtocol(proto->getDecl(), loc, source);
492+
// Find all of the protocols in the inheritance list.
493+
bool anyObject = false;
494+
for (const auto &found :
495+
getDirectlyInheritedNominalTypeDecls(decl, anyObject)) {
496+
if (auto proto = dyn_cast<ProtocolDecl>(found.second))
497+
addProtocol(proto, found.first, source);
507498
}
508499
}
509500

lib/AST/Decl.cpp

Lines changed: 43 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "swift/AST/LazyResolver.h"
3232
#include "swift/AST/ASTMangler.h"
3333
#include "swift/AST/Module.h"
34+
#include "swift/AST/NameLookup.h"
3435
#include "swift/AST/NameLookupRequests.h"
3536
#include "swift/AST/ParameterList.h"
3637
#include "swift/AST/Pattern.h"
@@ -3538,41 +3539,20 @@ ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc,
35383539
llvm::TinyPtrVector<ProtocolDecl *>
35393540
ProtocolDecl::getInheritedProtocols() const {
35403541
llvm::TinyPtrVector<ProtocolDecl *> result;
3541-
3542-
// FIXME: Gather inherited protocols from the "inherited" list.
3543-
// We shouldn't need this, but it shows up in recursive invocations.
3544-
if (!isRequirementSignatureComputed()) {
3545-
SmallPtrSet<ProtocolDecl *, 4> known;
3546-
if (Bits.ProtocolDecl.ComputingInheritedProtocols) return result;
3547-
3548-
auto *self = const_cast<ProtocolDecl *>(this);
3549-
self->Bits.ProtocolDecl.ComputingInheritedProtocols = true;
3550-
for (unsigned index : indices(getInherited())) {
3551-
if (auto type = getInheritedType(index)) {
3552-
// Only protocols can appear in the inheritance clause
3553-
// of a protocol -- anything else should get diagnosed
3554-
// elsewhere.
3555-
if (type->isExistentialType()) {
3556-
auto layout = type->getExistentialLayout();
3557-
for (auto protoTy : layout.getProtocols()) {
3558-
auto *protoDecl = protoTy->getDecl();
3559-
if (known.insert(protoDecl).second)
3560-
result.push_back(protoDecl);
3561-
}
3562-
}
3563-
}
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);
35643551
}
3565-
self->Bits.ProtocolDecl.ComputingInheritedProtocols = false;
3566-
return result;
35673552
}
35683553

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

@@ -3643,40 +3623,44 @@ bool ProtocolDecl::walkInheritedProtocols(
36433623
bool ProtocolDecl::inheritsFrom(const ProtocolDecl *super) const {
36443624
if (this == super)
36453625
return false;
3646-
3647-
auto allProtocols = getLocalProtocols();
3648-
return std::find(allProtocols.begin(), allProtocols.end(), super)
3649-
!= 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+
});
36503633
}
36513634

36523635
bool ProtocolDecl::requiresClassSlow() {
36533636
// Set this first to catch (invalid) circular inheritance.
36543637
Bits.ProtocolDecl.RequiresClassValid = true;
3638+
Bits.ProtocolDecl.RequiresClass = false;
36553639

36563640
// Quick check: @objc protocols require a class.
3657-
if (isObjC()) {
3658-
Bits.ProtocolDecl.RequiresClass = true;
3659-
return true;
3660-
}
3661-
3662-
// Otherwise, check if the inheritance clause contains a
3663-
// class-constrained existential.
3664-
//
3665-
// FIXME: Use the requirement signature if available.
3666-
Bits.ProtocolDecl.RequiresClass = false;
3667-
for (unsigned i : indices(getInherited())) {
3668-
Type type = getInheritedType(i);
3669-
assert(type && "Should have type checked inheritance clause by now");
3670-
if (type->isExistentialType()) {
3671-
auto layout = type->getExistentialLayout();
3672-
if (layout.requiresClass()) {
3673-
Bits.ProtocolDecl.RequiresClass = true;
3674-
return true;
3675-
}
3676-
}
3677-
if (type->getClassOrBoundGenericClass()) {
3678-
Bits.ProtocolDecl.RequiresClass = true;
3679-
return true;
3641+
if (isObjC())
3642+
return Bits.ProtocolDecl.RequiresClass = true;
3643+
3644+
// Determine the set of nominal types that this protocol inherits.
3645+
bool anyObject = false;
3646+
auto allInheritedNominals =
3647+
getDirectlyInheritedNominalTypeDecls(this, anyObject);
3648+
3649+
// Quick check: do we inherit AnyObject?
3650+
if (anyObject)
3651+
return Bits.ProtocolDecl.RequiresClass = true;
3652+
3653+
// Look through all of the inherited nominals for a superclass or a
3654+
// class-bound protocol.
3655+
for (const auto &found : allInheritedNominals) {
3656+
// Superclass bound.
3657+
if (isa<ClassDecl>(found.second))
3658+
return Bits.ProtocolDecl.RequiresClass = true;
3659+
3660+
// A protocol that might be class-constrained;
3661+
if (auto proto = dyn_cast<ProtocolDecl>(found.second)) {
3662+
if (proto->requiresClass())
3663+
return Bits.ProtocolDecl.RequiresClass = true;
36803664
}
36813665
}
36823666

lib/AST/DeclContext.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ ProtocolDecl *DeclContext::getAsProtocolExtensionContext() const {
9191
GenericTypeParamType *DeclContext::getProtocolSelfType() const {
9292
assert(getAsProtocolOrProtocolExtensionContext() && "not a protocol");
9393

94+
auto genericParams = getGenericParamsOfContext();
95+
96+
if (!genericParams) {
97+
if (auto proto = dyn_cast<ProtocolDecl>(this)) {
98+
getASTContext().getLazyResolver()
99+
->resolveDeclSignature(const_cast<ProtocolDecl *>(proto));
100+
genericParams = getGenericParamsOfContext();
101+
}
102+
}
103+
94104
return getGenericParamsOfContext()->getParams().front()
95105
->getDeclaredInterfaceType()
96106
->castTo<GenericTypeParamType>();

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())

0 commit comments

Comments
 (0)