Skip to content

[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

Merged

Conversation

DougGregor
Copy link
Member

Use the decl-base name lookup facilities (that don't recurse into the type checker) for various protocol-related queries, including:

  • Construction of the "conformance lookup table", which is used to figure out which protocols a given nominal type conforms to.
  • ProtocolDecl::requiresClass(), which determines whether a given protocol is class-bound
  • ProtocolDecl::getInheritedProtocols(), which would bounce between using the requirement signature and using the type checker.

…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.
@DougGregor
Copy link
Member Author

@swift-ci please smoke test

@DougGregor
Copy link
Member Author

@swift-ci please test source compatibility

@DougGregor DougGregor merged commit 8f36061 into swiftlang:master Aug 7, 2018
@DougGregor DougGregor deleted the protocol-decl-based-resolution branch August 7, 2018 03:45
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}}
Copy link
Contributor

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

Copy link
Member Author

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.
Copy link
Contributor

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?

Copy link
Member Author

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.

@@ -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(
Copy link
Contributor

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.
Copy link
Contributor

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

Copy link
Member Author

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.

@@ -1966,7 +1966,8 @@ resolveTypeDeclsToNominal(Evaluator &evaluator,
ASTContext &ctx,
ArrayRef<TypeDecl *> typeDecls,
SmallVectorImpl<ModuleDecl *> &modulesFound,
bool &anyObject) {
bool &anyObject,
llvm::SmallPtrSetImpl<TypeAliasDecl *> &typealiases) {
Copy link
Contributor

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();
Copy link
Contributor

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants