Skip to content

Commit 48fb227

Browse files
committed
[Name lookup] Factor out core “qualified lookup in a set of TypeDecls”.
Make the core lookupQualified() API accept an array of TypeDecls in which it should look, rather than looking into a Type. This is in preparation for breaking more type-checker dependencies in the name lookup code.
1 parent 081a6af commit 48fb227

File tree

2 files changed

+121
-45
lines changed

2 files changed

+121
-45
lines changed

include/swift/AST/DeclContext.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,24 @@ class alignas(1 << DeclContextAlignInBits) DeclContext {
486486
LazyResolver *typeResolver,
487487
SmallVectorImpl<ValueDecl *> &decls) const;
488488

489+
/// Look for the set of declarations with the given name within the
490+
/// given set of type declarations.
491+
///
492+
/// \param types The type declarations to look into.
493+
///
494+
/// \param member The member to search for.
495+
///
496+
/// \param options Options that control name lookup, based on the
497+
/// \c NL_* constants in \c NameLookupOptions.
498+
///
499+
/// \param[out] decls Will be populated with the declarations found by name
500+
/// lookup.
501+
///
502+
/// \returns true if anything was found.
503+
bool lookupQualified(ArrayRef<TypeDecl *> types, DeclName member,
504+
NLOptions options,
505+
SmallVectorImpl<ValueDecl *> &decls) const;
506+
489507
/// Perform qualified lookup for the given member in the given module.
490508
bool lookupQualified(ModuleDecl *module, DeclName member, NLOptions options,
491509
SmallVectorImpl<ValueDecl *> &decls) const;

lib/AST/NameLookup.cpp

Lines changed: 103 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1622,6 +1622,49 @@ static bool finishLookup(const DeclContext *dc, NLOptions options,
16221622
return !decls.empty();
16231623
}
16241624

1625+
/// Inspect the given type to determine which nominal type declarations it
1626+
/// directly references, to facilitate name lookup into those types.
1627+
static void extractDirectlyReferencedNominalTypes(
1628+
Type type, SmallVectorImpl<NominalTypeDecl *> &decls) {
1629+
if (auto nominal = type->getAnyNominal()) {
1630+
decls.push_back(nominal);
1631+
return;
1632+
}
1633+
1634+
if (auto archetypeTy = type->getAs<ArchetypeType>()) {
1635+
// Look in the protocols to which the archetype conforms (always).
1636+
for (auto proto : archetypeTy->getConformsTo())
1637+
decls.push_back(proto);
1638+
1639+
// Look into the superclasses of this archetype.
1640+
if (auto superclass = archetypeTy->getSuperclass()) {
1641+
if (auto superclassDecl = superclass->getClassOrBoundGenericClass())
1642+
decls.push_back(superclassDecl);
1643+
}
1644+
1645+
return;
1646+
}
1647+
1648+
if (auto compositionTy = type->getAs<ProtocolCompositionType>()) {
1649+
auto layout = compositionTy->getExistentialLayout();
1650+
1651+
for (auto proto : layout.getProtocols()) {
1652+
auto *protoDecl = proto->getDecl();
1653+
decls.push_back(protoDecl);
1654+
}
1655+
1656+
if (auto superclass = layout.explicitSuperclass) {
1657+
auto *superclassDecl = superclass->getClassOrBoundGenericClass();
1658+
if (superclassDecl)
1659+
decls.push_back(superclassDecl);
1660+
}
1661+
1662+
return;
1663+
}
1664+
1665+
llvm_unreachable("Not a type containing nominal types?");
1666+
}
1667+
16251668
bool DeclContext::lookupQualified(Type type,
16261669
DeclName member,
16271670
NLOptions options,
@@ -1638,73 +1681,88 @@ bool DeclContext::lookupQualified(Type type,
16381681
if (auto moduleTy = type->getAs<ModuleType>())
16391682
return lookupQualified(moduleTy->getModule(), member, options, decls);
16401683

1641-
if (!typeResolver)
1642-
typeResolver = getASTContext().getLazyResolver();
1684+
// Figure out which nominal types we will look into.
1685+
SmallVector<NominalTypeDecl *, 4> nominalTypesToLookInto;
1686+
extractDirectlyReferencedNominalTypes(type, nominalTypesToLookInto);
1687+
1688+
SmallVector<TypeDecl *, 4> declsToLookInto(nominalTypesToLookInto.begin(),
1689+
nominalTypesToLookInto.end());
1690+
return lookupQualified(declsToLookInto, member, options, decls);
1691+
}
1692+
1693+
bool DeclContext::lookupQualified(ArrayRef<TypeDecl *> typeDecls,
1694+
DeclName member,
1695+
NLOptions options,
1696+
SmallVectorImpl<ValueDecl *> &decls) const {
1697+
using namespace namelookup;
1698+
assert(decls.empty() && "additive lookup not supported");
1699+
1700+
// If we have a module, look in it.
1701+
if (typeDecls.size() == 1 && isa<ModuleDecl>(typeDecls[0])) {
1702+
return lookupQualified(cast<ModuleDecl>(typeDecls[0]), member, options,
1703+
decls);
1704+
}
16431705

16441706
// Configure lookup and dig out the tracker.
16451707
ReferencedNameTracker *tracker = nullptr;
16461708
bool isLookupCascading;
16471709
configureLookup(this, options, tracker, isLookupCascading);
16481710

1649-
// The set of nominal type declarations we should (and have) visited.
1711+
// Tracking for the nominal types we'll visit.
16501712
SmallVector<NominalTypeDecl *, 4> stack;
16511713
llvm::SmallPtrSet<NominalTypeDecl *, 4> visited;
1714+
bool sawClassDecl = false;
16521715

1653-
// Note that we don't have to visit the superclass of a protocol.
1654-
// If we started with an archetype or existential, we'll visit the
1655-
// superclass because we will have added it to the stack upfront.
1656-
//
1657-
// If we started with a concrete class conforming to a protocol
1658-
// with a superclass, we will visit the superclass from the
1659-
// concrete type.
1660-
bool checkProtocolSuperclass = false;
1716+
// Add the given nominal type to the stack.
1717+
auto addNominalType = [&](NominalTypeDecl *nominal) {
1718+
if (!visited.insert(nominal).second)
1719+
return false;
1720+
1721+
if (isa<ClassDecl>(nominal))
1722+
sawClassDecl = true;
16611723

1662-
// Handle nominal types.
1663-
bool wantProtocolMembers = (options & NL_ProtocolMembers);
1664-
if (auto nominal = type->getAnyNominal()) {
1665-
visited.insert(nominal);
16661724
stack.push_back(nominal);
1725+
return true;
1726+
};
16671727

1668-
if (isa<ProtocolDecl>(nominal))
1669-
checkProtocolSuperclass = true;
1670-
}
1671-
// Handle archetypes
1672-
else if (auto archetypeTy = type->getAs<ArchetypeType>()) {
1673-
// Look in the protocols to which the archetype conforms (always).
1674-
for (auto proto : archetypeTy->getConformsTo())
1675-
if (visited.insert(proto).second)
1676-
stack.push_back(proto);
1728+
// Look through the type declarations we were given, resolving
1729+
ASTContext &ctx = getASTContext();
1730+
for (auto typeDecl : typeDecls) {
1731+
// Add nominal types directly.
1732+
if (auto nominal = dyn_cast<NominalTypeDecl>(typeDecl)) {
1733+
addNominalType(nominal);
1734+
continue;
1735+
}
16771736

1678-
// Look into the superclasses of this archetype.
1679-
if (auto superclass = archetypeTy->getSuperclass())
1680-
if (auto superclassDecl = superclass->getClassOrBoundGenericClass())
1681-
if (visited.insert(superclassDecl).second)
1682-
stack.push_back(superclassDecl);
1683-
}
1684-
// Handle protocol compositions.
1685-
else if (auto compositionTy = type->getAs<ProtocolCompositionType>()) {
1686-
auto layout = compositionTy->getExistentialLayout();
1737+
// For typealiases, extract nominal type declarations from the underlying
1738+
// type of the typealias.
1739+
if (auto typealias = dyn_cast<TypeAliasDecl>(typeDecl)) {
1740+
SmallVector<NominalTypeDecl *, 4> nominalTypeDecls;
1741+
if (!typealias->getUnderlyingTypeLoc().getType()) {
1742+
auto lazyResolver = ctx.getLazyResolver();
1743+
assert(lazyResolver && "Cannot resolve underlying type of typealias");
1744+
lazyResolver->resolveDeclSignature(typealias);
1745+
}
16871746

1688-
for (auto proto : layout.getProtocols()) {
1689-
auto *protoDecl = proto->getDecl();
1690-
if (visited.insert(protoDecl).second)
1691-
stack.push_back(protoDecl);
1747+
extractDirectlyReferencedNominalTypes(
1748+
typealias->getUnderlyingTypeLoc().getType(),
1749+
nominalTypeDecls);
1750+
for (auto nominal : nominalTypeDecls)
1751+
addNominalType(nominal);
1752+
continue;
16921753
}
16931754

1694-
if (auto superclass = layout.explicitSuperclass) {
1695-
auto *superclassDecl = superclass->getClassOrBoundGenericClass();
1696-
if (visited.insert(superclassDecl).second)
1697-
stack.push_back(superclassDecl);
1698-
}
1699-
} else {
1700-
llvm_unreachable("Bad type for qualified lookup");
1755+
llvm_unreachable("Cannot look into multiple modules "
1756+
"or any type parameter");
17011757
}
17021758

17031759
// Whether we only want to return complete object initializers.
17041760
bool onlyCompleteObjectInits = false;
17051761

17061762
// Visit all of the nominal types we know about, discovering any others
17071763
// we need along the way.
1764+
auto typeResolver = ctx.getLazyResolver();
1765+
bool wantProtocolMembers = (options & NL_ProtocolMembers);
17081766
while (!stack.empty()) {
17091767
auto current = stack.back();
17101768
stack.pop_back();
@@ -1759,7 +1817,7 @@ bool DeclContext::lookupQualified(Type type,
17591817
if (!wantProtocolMembers && !currentIsProtocol)
17601818
continue;
17611819

1762-
if (checkProtocolSuperclass) {
1820+
if (!sawClassDecl) {
17631821
if (auto *protoDecl = dyn_cast<ProtocolDecl>(current)) {
17641822
if (auto superclassDecl = protoDecl->getSuperclassDecl()) {
17651823
visited.insert(superclassDecl);

0 commit comments

Comments
 (0)