Skip to content

Commit 1cf6ef1

Browse files
committed
[Name lookup] Factor out AnyObject lookup.
AnyObject lookup is a completely separate path from normal qualified lookup, so separate it out and pull out the common bits.
1 parent c83e890 commit 1cf6ef1

File tree

2 files changed

+153
-116
lines changed

2 files changed

+153
-116
lines changed

include/swift/AST/DeclContext.h

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

489+
/// Perform \c AnyObject lookup for the given member.
490+
bool lookupAnyObject(DeclName member, NLOptions options,
491+
SmallVectorImpl<ValueDecl *> &decls) const;
492+
489493
/// Look up all Objective-C methods with the given selector visible
490494
/// in the enclosing module.
491495
void lookupAllObjCMethods(

lib/AST/NameLookup.cpp

Lines changed: 149 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,21 +1523,29 @@ Type AbstractStorageDecl::getStorageInterfaceType() const {
15231523
llvm_unreachable("unhandled storage decl kind");
15241524
}
15251525

1526-
bool DeclContext::lookupQualified(Type type,
1527-
DeclName member,
1528-
NLOptions options,
1529-
LazyResolver *typeResolver,
1530-
SmallVectorImpl<ValueDecl *> &decls) const {
1531-
using namespace namelookup;
1532-
assert(decls.empty() && "additive lookup not supported");
1526+
/// Configure name lookup for the given declaration context and options.
1527+
///
1528+
/// This utility is used by qualified name lookup.
1529+
static void configureLookup(const DeclContext *dc,
1530+
NLOptions &options,
1531+
ReferencedNameTracker *&tracker,
1532+
bool &isLookupCascading) {
1533+
auto &ctx = dc->getASTContext();
1534+
if (!ctx.LangOpts.EnableAccessControl)
1535+
options |= NL_IgnoreAccessControl;
15331536

1534-
if (!typeResolver)
1535-
typeResolver = getASTContext().getLazyResolver();
1536-
1537-
auto checkLookupCascading = [this, options]() -> Optional<bool> {
1537+
// Find the dependency tracker we'll need for this lookup.
1538+
tracker = nullptr;
1539+
if (auto containingSourceFile =
1540+
dyn_cast<SourceFile>(dc->getModuleScopeContext())) {
1541+
tracker = containingSourceFile->getReferencedNameTracker();
1542+
}
1543+
1544+
auto checkLookupCascading = [dc, options]() -> Optional<bool> {
15381545
switch (static_cast<unsigned>(options & NL_KnownDependencyMask)) {
15391546
case 0:
1540-
return isCascadingContextForLookup(/*functionsAreNonCascading=*/false);
1547+
return dc->isCascadingContextForLookup(
1548+
/*functionsAreNonCascading=*/false);
15411549
case NL_KnownNonCascadingDependency:
15421550
return false;
15431551
case NL_KnownCascadingDependency:
@@ -1554,14 +1562,93 @@ bool DeclContext::lookupQualified(Type type,
15541562
}
15551563
};
15561564

1565+
// Determine whether a lookup here will cascade.
1566+
isLookupCascading = false;
1567+
if (tracker) {
1568+
if (auto maybeLookupCascade = checkLookupCascading())
1569+
isLookupCascading = maybeLookupCascade.getValue();
1570+
else
1571+
tracker = nullptr;
1572+
}
1573+
}
1574+
1575+
/// Determine whether the given declaration is an acceptable lookup
1576+
/// result when searching from the given DeclContext.
1577+
static bool isAcceptableLookupResult(const DeclContext *dc,
1578+
NLOptions options,
1579+
ValueDecl *decl,
1580+
bool onlyCompleteObjectInits) {
1581+
// Filter out designated initializers, if requested.
1582+
if (onlyCompleteObjectInits) {
1583+
if (auto ctor = dyn_cast<ConstructorDecl>(decl)) {
1584+
if (isa<ClassDecl>(ctor->getDeclContext()) && !ctor->isInheritable())
1585+
return false;
1586+
} else {
1587+
return false;
1588+
}
1589+
}
1590+
1591+
// Ignore stub implementations.
1592+
if (auto ctor = dyn_cast<ConstructorDecl>(decl)) {
1593+
if (ctor->hasStubImplementation())
1594+
return false;
1595+
}
1596+
1597+
// Check access.
1598+
if (!(options & NL_IgnoreAccessControl)) {
1599+
return decl->isAccessibleFrom(dc);
1600+
}
1601+
1602+
return true;
1603+
}
1604+
1605+
/// Only name lookup has gathered a set of results, perform any necessary
1606+
/// steps to prune the result set before returning it to the caller.
1607+
static bool finishLookup(const DeclContext *dc, NLOptions options,
1608+
SmallVectorImpl<ValueDecl *> &decls) {
1609+
// If we're supposed to remove overridden declarations, do so now.
1610+
if (options & NL_RemoveOverridden)
1611+
removeOverriddenDecls(decls);
1612+
1613+
// If we're supposed to remove shadowed/hidden declarations, do so now.
1614+
ModuleDecl *M = dc->getParentModule();
1615+
if (options & NL_RemoveNonVisible)
1616+
removeShadowedDecls(decls, M);
1617+
1618+
if (auto *debugClient = M->getDebugClient())
1619+
filterForDiscriminator(decls, debugClient);
1620+
1621+
// We're done. Report success/failure.
1622+
return !decls.empty();
1623+
}
1624+
1625+
bool DeclContext::lookupQualified(Type type,
1626+
DeclName member,
1627+
NLOptions options,
1628+
LazyResolver *typeResolver,
1629+
SmallVectorImpl<ValueDecl *> &decls) const {
1630+
using namespace namelookup;
1631+
assert(decls.empty() && "additive lookup not supported");
1632+
1633+
// Handle AnyObject lookup.
1634+
if (type->isAnyObject())
1635+
return lookupAnyObject(member, options, decls);
1636+
1637+
if (!typeResolver)
1638+
typeResolver = getASTContext().getLazyResolver();
1639+
1640+
// Configure lookup and dig out the tracker.
1641+
ReferencedNameTracker *tracker = nullptr;
1642+
bool isLookupCascading;
1643+
configureLookup(this, options, tracker, isLookupCascading);
1644+
15571645
// Look for module references.
15581646
if (auto moduleTy = type->getAs<ModuleType>()) {
15591647
ModuleDecl *module = moduleTy->getModule();
15601648
auto topLevelScope = getModuleScopeContext();
15611649
if (module == topLevelScope->getParentModule()) {
1562-
if (auto maybeLookupCascade = checkLookupCascading()) {
1563-
recordLookupOfTopLevelName(topLevelScope, member,
1564-
maybeLookupCascade.getValue());
1650+
if (tracker) {
1651+
recordLookupOfTopLevelName(topLevelScope, member, isLookupCascading);
15651652
}
15661653
lookupInModule(module, /*accessPath=*/{}, member, decls,
15671654
NLKind::QualifiedLookup, ResolutionKind::Overloadable,
@@ -1603,10 +1690,6 @@ bool DeclContext::lookupQualified(Type type,
16031690
return !decls.empty();
16041691
}
16051692

1606-
auto &ctx = getASTContext();
1607-
if (!ctx.LangOpts.EnableAccessControl)
1608-
options |= NL_IgnoreAccessControl;
1609-
16101693
// The set of nominal type declarations we should (and have) visited.
16111694
SmallVector<NominalTypeDecl *, 4> stack;
16121695
llvm::SmallPtrSet<NominalTypeDecl *, 4> visited;
@@ -1622,7 +1705,6 @@ bool DeclContext::lookupQualified(Type type,
16221705

16231706
// Handle nominal types.
16241707
bool wantProtocolMembers = (options & NL_ProtocolMembers);
1625-
bool wantLookupInAllClasses = false;
16261708
if (auto nominal = type->getAnyNominal()) {
16271709
visited.insert(nominal);
16281710
stack.push_back(nominal);
@@ -1647,10 +1729,6 @@ bool DeclContext::lookupQualified(Type type,
16471729
else if (auto compositionTy = type->getAs<ProtocolCompositionType>()) {
16481730
auto layout = compositionTy->getExistentialLayout();
16491731

1650-
if (layout.isAnyObject() &&
1651-
(options & NL_DynamicLookup))
1652-
wantLookupInAllClasses = true;
1653-
16541732
for (auto proto : layout.getProtocols()) {
16551733
auto *protoDecl = proto->getDecl();
16561734
if (visited.insert(protoDecl).second)
@@ -1666,46 +1744,8 @@ bool DeclContext::lookupQualified(Type type,
16661744
llvm_unreachable("Bad type for qualified lookup");
16671745
}
16681746

1669-
// Allow filtering of the visible declarations based on various
1670-
// criteria.
1747+
// Whether we only want to return complete object initializers.
16711748
bool onlyCompleteObjectInits = false;
1672-
auto isAcceptableDecl = [&](NominalTypeDecl *current, ValueDecl *decl) -> bool {
1673-
// Filter out designated initializers, if requested.
1674-
if (onlyCompleteObjectInits) {
1675-
if (auto ctor = dyn_cast<ConstructorDecl>(decl)) {
1676-
if (isa<ClassDecl>(ctor->getDeclContext()) &&
1677-
!ctor->isInheritable())
1678-
return false;
1679-
} else {
1680-
return false;
1681-
}
1682-
}
1683-
1684-
// Ignore stub implementations.
1685-
if (auto ctor = dyn_cast<ConstructorDecl>(decl)) {
1686-
if (ctor->hasStubImplementation())
1687-
return false;
1688-
}
1689-
1690-
// Check access.
1691-
if (!(options & NL_IgnoreAccessControl)) {
1692-
return decl->isAccessibleFrom(this);
1693-
}
1694-
1695-
return true;
1696-
};
1697-
1698-
ReferencedNameTracker *tracker = nullptr;
1699-
if (auto containingSourceFile = dyn_cast<SourceFile>(getModuleScopeContext()))
1700-
tracker = containingSourceFile->getReferencedNameTracker();
1701-
1702-
bool isLookupCascading;
1703-
if (tracker) {
1704-
if (auto maybeLookupCascade = checkLookupCascading())
1705-
isLookupCascading = maybeLookupCascade.getValue();
1706-
else
1707-
tracker = nullptr;
1708-
}
17091749

17101750
// Visit all of the nominal types we know about, discovering any others
17111751
// we need along the way.
@@ -1732,7 +1772,8 @@ bool DeclContext::lookupQualified(Type type,
17321772
if ((options & NL_OnlyTypes) && !isa<TypeDecl>(decl))
17331773
continue;
17341774

1735-
if (isAcceptableDecl(current, decl))
1775+
if (isAcceptableLookupResult(this, options, decl,
1776+
onlyCompleteObjectInits))
17361777
decls.push_back(decl);
17371778
}
17381779

@@ -1784,66 +1825,58 @@ bool DeclContext::lookupQualified(Type type,
17841825
wantProtocolMembers = false;
17851826
}
17861827

1787-
// If we want to perform lookup into all classes, do so now.
1788-
if (wantLookupInAllClasses) {
1789-
if (tracker)
1790-
tracker->addDynamicLookupName(member.getBaseName(), isLookupCascading);
1791-
1792-
// Collect all of the visible declarations.
1793-
SmallVector<ValueDecl *, 4> allDecls;
1794-
forAllVisibleModules(this, [&](ModuleDecl::ImportedModule import) {
1795-
import.second->lookupClassMember(import.first, member, allDecls);
1796-
});
1797-
1798-
// For each declaration whose context is not something we've
1799-
// already visited above, add it to the list of declarations.
1800-
llvm::SmallPtrSet<ValueDecl *, 4> knownDecls;
1801-
for (auto decl : allDecls) {
1802-
// If we're performing a type lookup, don't even attempt to validate
1803-
// the decl if its not a type.
1804-
if ((options & NL_OnlyTypes) && !isa<TypeDecl>(decl))
1805-
continue;
1828+
return finishLookup(this, options, decls);
1829+
}
18061830

1807-
// If the declaration is not @objc, it cannot be called dynamically.
1808-
if (!decl->isObjC())
1809-
continue;
1831+
bool DeclContext::lookupAnyObject(DeclName member, NLOptions options,
1832+
SmallVectorImpl<ValueDecl *> &decls) const {
1833+
// Configure lookup and dig out the tracker.
1834+
ReferencedNameTracker *tracker = nullptr;
1835+
bool isLookupCascading;
1836+
configureLookup(this, options, tracker, isLookupCascading);
18101837

1811-
// If the declaration has an override, name lookup will also have
1812-
// found the overridden method. Skip this declaration, because we
1813-
// prefer the overridden method.
1814-
if (decl->getOverriddenDecl())
1815-
continue;
1838+
// Record this lookup.
1839+
if (tracker)
1840+
tracker->addDynamicLookupName(member.getBaseName(), isLookupCascading);
18161841

1817-
auto dc = decl->getDeclContext();
1818-
auto nominal = dyn_cast<NominalTypeDecl>(dc);
1819-
if (!nominal) {
1820-
auto ext = cast<ExtensionDecl>(dc);
1821-
nominal = ext->getExtendedType()->getAnyNominal();
1822-
assert(nominal && "Couldn't find nominal type?");
1823-
}
1842+
// Type-only lookup won't find anything on AnyObject.
1843+
if (options & NL_OnlyTypes)
1844+
return false;
18241845

1825-
// If we didn't visit this nominal type above, add this
1826-
// declaration to the list.
1827-
if (!visited.count(nominal) && knownDecls.insert(decl).second &&
1828-
isAcceptableDecl(nominal, decl))
1829-
decls.push_back(decl);
1830-
}
1831-
}
1846+
// Collect all of the visible declarations.
1847+
SmallVector<ValueDecl *, 4> allDecls;
1848+
forAllVisibleModules(this, [&](ModuleDecl::ImportedModule import) {
1849+
import.second->lookupClassMember(import.first, member, allDecls);
1850+
});
18321851

1833-
// If we're supposed to remove overridden declarations, do so now.
1834-
if (options & NL_RemoveOverridden)
1835-
removeOverriddenDecls(decls);
1852+
// For each declaration whose context is not something we've
1853+
// already visited above, add it to the list of declarations.
1854+
llvm::SmallPtrSet<ValueDecl *, 4> knownDecls;
1855+
for (auto decl : allDecls) {
1856+
// If the declaration is not @objc, it cannot be called dynamically.
1857+
if (!decl->isObjC())
1858+
continue;
18361859

1837-
// If we're supposed to remove shadowed/hidden declarations, do so now.
1838-
ModuleDecl *M = getParentModule();
1839-
if (options & NL_RemoveNonVisible)
1840-
removeShadowedDecls(decls, M);
1860+
// If the declaration has an override, name lookup will also have
1861+
// found the overridden method. Skip this declaration, because we
1862+
// prefer the overridden method.
1863+
if (decl->getOverriddenDecl())
1864+
continue;
18411865

1842-
if (auto *debugClient = M->getDebugClient())
1843-
filterForDiscriminator(decls, debugClient);
1866+
auto dc = decl->getDeclContext();
1867+
auto nominal = dc->getAsNominalTypeOrNominalTypeExtensionContext();
1868+
assert(nominal && "Couldn't find nominal type?");
1869+
1870+
// If we didn't see this declaration before, and it's an acceptable
1871+
// result, add it to the list.
1872+
// declaration to the list.
1873+
if (knownDecls.insert(decl).second &&
1874+
isAcceptableLookupResult(this, options, decl,
1875+
/*onlyCompleteObjectInits=*/false))
1876+
decls.push_back(decl);
1877+
}
18441878

1845-
// We're done. Report success/failure.
1846-
return !decls.empty();
1879+
return finishLookup(this, options, decls);
18471880
}
18481881

18491882
void DeclContext::lookupAllObjCMethods(

0 commit comments

Comments
 (0)