-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Name lookup] Use decl-based name lookup for protocol-related queries #18530
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Name lookup] Use decl-based name lookup for protocol-related queries #18530
Conversation
…able. Add API to get all of the nominal types directly referenced from the inheritance clause of a given declaration. Use that to find the protocols to enter into the conformance lookup table based on a given declaration, without going through the type checker [*]. [*] Except for unqualified lookup still needing to use the type checker.
…ion. Resolving whether a protocol is class-bound only requires declaration-based resolution (not the full type checker), so switch over to those APIs.
…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.
Ensuring that we've computed the list of "inherited" protocols is part of finalizeType(), now.
…heritedType(). Simple checks for the presence of a protocol in the “inherited” list should only require a scan through that list + name lookup; use those facilities instead of recursing through the type checker.
@swift-ci please smoke test |
@swift-ci please test source compatibility |
struct S4 : P, P { } // expected-error {{duplicate inheritance from 'P'}} | ||
struct S4 : P, P { } // FIXME: expected-error {{duplicate inheritance from 'P'}} | ||
// expected-error@-1{{redundant conformance of 'S4' to protocol 'P'}} | ||
// expected-note@-2{{'S4' declares conformance to protocol 'P' here}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the duplicate diagnostics come from checkInheritanceClause()
and the GSB, respectively
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. I'm going to narrow the one in checkInheritanceClause()
to eliminate the duplication. See #18700
nominalDecls.insert(nominalDecls.end(), | ||
underlyingNominalReferences.begin(), | ||
underlyingNominalReferences.end()); | ||
|
||
// Recognize Swift.AnyObject directly. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Swift.AnyObject should have been deserialized and type checked -- would that make this simpler?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it doesn't, because we need this check to work when building the standard library, and don't want to rely on Swift.AnyObject
having been type-checked first.
include/swift/AST/NameLookup.h
Outdated
@@ -356,18 +356,23 @@ void lookupInModule(ModuleDecl *module, ModuleDecl::AccessPathTy accessPath, | |||
/// "inherited" by the given declaration at a particular position in the | |||
/// list of "inherited" types. | |||
/// | |||
/// Add anything we find to the | |||
/// Add anything we find to the \c result vector. If we come across the | |||
/// AnyObject type, set \c anyObject true. | |||
void getDirectlyInheritedNominalTypeDecls( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be cleaner to return a struct or a pair here instead of having two out parameters?
@@ -592,10 +592,6 @@ ModuleDecl::lookupConformance(Type type, ProtocolDecl *protocol) { | |||
// existential's list of conformances and the existential conforms to | |||
// itself. | |||
if (type->isExistentialType()) { | |||
// FIXME: Recursion break. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure this is not needed? existentialConformsToSelf() can call back into validateDecl() IIRC
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer! It uses simpler queries that don't go through validateDecl()
, now that getInheritedProtocols()
is all decl-lookup-based.
lib/AST/NameLookup.cpp
Outdated
@@ -1966,7 +1966,8 @@ resolveTypeDeclsToNominal(Evaluator &evaluator, | |||
ASTContext &ctx, | |||
ArrayRef<TypeDecl *> typeDecls, | |||
SmallVectorImpl<ModuleDecl *> &modulesFound, | |||
bool &anyObject) { | |||
bool &anyObject, | |||
llvm::SmallPtrSetImpl<TypeAliasDecl *> &typealiases) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even more reason to use a real return type :)
@@ -91,6 +91,16 @@ ProtocolDecl *DeclContext::getAsProtocolExtensionContext() const { | |||
GenericTypeParamType *DeclContext::getProtocolSelfType() const { | |||
assert(getAsProtocolOrProtocolExtensionContext() && "not a protocol"); | |||
|
|||
auto genericParams = getGenericParamsOfContext(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ProtocolDecl::createGenericParamsIfMissing() is lighter weight
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, thank you!
Use the decl-base name lookup facilities (that don't recurse into the type checker) for various protocol-related queries, including:
ProtocolDecl::requiresClass()
, which determines whether a given protocol is class-boundProtocolDecl::getInheritedProtocols()
, which would bounce between using the requirement signature and using the type checker.