Skip to content

Commit 90f6e5b

Browse files
committed
xxx
1 parent bfffbbf commit 90f6e5b

20 files changed

+442
-502
lines changed

include/swift/AST/ASTContext.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -745,16 +745,18 @@ class ASTContext final {
745745
/// \param isInstanceMethod Whether we are looking for an instance method
746746
/// (vs. a class method).
747747
///
748+
/// \param swiftOnly If true, only loads methods from imported Swift modules,
749+
/// skipping the Clang importer.
750+
///
748751
/// \param previousGeneration The previous generation with which this
749752
/// callback was invoked. The list of methods will already contain all of
750753
/// the results from generations up and including \c previousGeneration.
751754
///
752755
/// \param methods The list of @objc methods in this class that have this
753756
/// selector and are instance/class methods as requested. This list will be
754757
/// extended with any methods found in subsequent generations.
755-
void loadObjCMethods(ClassDecl *classDecl,
756-
ObjCSelector selector,
757-
bool isInstanceMethod,
758+
void loadObjCMethods(ClassDecl *classDecl, ObjCSelector selector,
759+
bool isInstanceMethod, bool swiftOnly,
758760
unsigned previousGeneration,
759761
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods);
760762

include/swift/AST/Decl.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3874,13 +3874,16 @@ using AncestryOptions = OptionSet<AncestryFlags>;
38743874
/// The type of the decl itself is a MetatypeType; use getDeclaredType()
38753875
/// to get the declared type ("Complex" in the above example).
38763876
class ClassDecl final : public NominalTypeDecl {
3877+
friend class NominalTypeDecl;
3878+
friend class ObjCMethodDirectLookupRequest;
3879+
38773880
class ObjCMethodLookupTable;
38783881

38793882
SourceLoc ClassLoc;
38803883
ObjCMethodLookupTable *ObjCMethodLookup = nullptr;
38813884

3882-
/// Create the Objective-C member lookup table.
3883-
void createObjCMethodLookup();
3885+
/// Prepare the Objective-C member lookup table.
3886+
void prepareObjCMethodLookup();
38843887

38853888
struct {
38863889
/// The superclass decl and a bit to indicate whether the
@@ -4117,11 +4120,8 @@ class ClassDecl final : public NominalTypeDecl {
41174120
///
41184121
/// \param isInstance Whether we are looking for an instance method
41194122
/// (vs. a class method).
4120-
MutableArrayRef<AbstractFunctionDecl *> lookupDirect(ObjCSelector selector,
4121-
bool isInstance);
4122-
4123-
/// Record the presence of an @objc method with the given selector.
4124-
void recordObjCMethod(AbstractFunctionDecl *method, ObjCSelector selector);
4123+
TinyPtrVector<AbstractFunctionDecl *> lookupDirect(ObjCSelector selector,
4124+
bool isInstance) const;
41254125

41264126
/// Get all the members of this class, synthesizing any implicit members
41274127
/// that appear in the vtable if needed.

include/swift/AST/Identifier.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,8 +891,15 @@ class ObjCSelector {
891891
friend bool operator>=(ObjCSelector lhs, ObjCSelector rhs) {
892892
return lhs.compare(rhs) >= 0;
893893
}
894+
895+
friend llvm::hash_code hash_value(ObjCSelector selector) {
896+
using llvm::hash_value;
897+
return hash_value(selector.getOpaqueValue());
898+
}
894899
};
895900

901+
void simple_display(llvm::raw_ostream &out, ObjCSelector selector);
902+
896903
} // end namespace swift
897904

898905
namespace llvm {

include/swift/AST/NameLookupRequests.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,24 @@ class LookupConformanceInModuleRequest
770770
ProtocolConformanceRef result) const;
771771
};
772772

773+
class ObjCMethodDirectLookupRequest
774+
: public SimpleRequest<ObjCMethodDirectLookupRequest,
775+
TinyPtrVector<AbstractFunctionDecl *>(
776+
ClassDecl *, ObjCSelector, bool),
777+
RequestFlags::Uncached> {
778+
public:
779+
using SimpleRequest::SimpleRequest;
780+
781+
private:
782+
friend SimpleRequest;
783+
784+
// Evaluation.
785+
TinyPtrVector<AbstractFunctionDecl *> evaluate(Evaluator &evaluator,
786+
ClassDecl *CD,
787+
ObjCSelector selector,
788+
bool isInstance) const;
789+
};
790+
773791
#define SWIFT_TYPEID_ZONE NameLookup
774792
#define SWIFT_TYPEID_HEADER "swift/AST/NameLookupTypeIDZone.def"
775793
#include "swift/Basic/DefineTypeIDZone.h"

include/swift/AST/NameLookupTypeIDZone.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,7 @@ SWIFT_REQUEST(NameLookup, LookupPostfixOperatorRequest,
9797
SWIFT_REQUEST(NameLookup, LookupPrecedenceGroupRequest,
9898
PrecedenceGroupDecl *(OperatorLookupDescriptor),
9999
Cached, NoLocationInfo)
100+
SWIFT_REQUEST(NameLookup, ObjCMethodDirectLookupRequest,
101+
TinyPtrVector<AbstractFunctionDecl *>(ClassDecl *, ObjCSelector,
102+
bool),
103+
Uncached, NoLocationInfo)

include/swift/AST/SourceFile.h

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -263,22 +263,6 @@ class SourceFile final : public FileUnit {
263263
llvm::DenseMap<ObjCSelector, llvm::TinyPtrVector<AbstractFunctionDecl *>>
264264
ObjCMethods;
265265

266-
/// List of Objective-C methods, which is used for checking unintended
267-
/// Objective-C overrides.
268-
std::vector<AbstractFunctionDecl *> ObjCMethodList;
269-
270-
/// An unsatisfied, optional @objc requirement in a protocol conformance.
271-
using ObjCUnsatisfiedOptReq = std::pair<DeclContext *, AbstractFunctionDecl *>;
272-
273-
/// List of optional @objc protocol requirements that have gone
274-
/// unsatisfied, which might conflict with other Objective-C methods.
275-
std::vector<ObjCUnsatisfiedOptReq> ObjCUnsatisfiedOptReqs;
276-
277-
using ObjCMethodConflict = std::tuple<ClassDecl *, ObjCSelector, bool>;
278-
279-
/// List of Objective-C member conflicts we have found during type checking.
280-
std::vector<ObjCMethodConflict> ObjCMethodConflicts;
281-
282266
/// Describes what kind of file this is, which can affect some type checking
283267
/// and other behavior.
284268
const SourceFileKind Kind;

lib/AST/ASTContext.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,14 +1486,16 @@ void ASTContext::loadExtensions(NominalTypeDecl *nominal,
14861486
}
14871487

14881488
void ASTContext::loadObjCMethods(
1489-
ClassDecl *classDecl,
1490-
ObjCSelector selector,
1491-
bool isInstanceMethod,
1492-
unsigned previousGeneration,
1493-
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods) {
1489+
ClassDecl *classDecl, ObjCSelector selector, bool isInstanceMethod,
1490+
bool swiftOnly, unsigned previousGeneration,
1491+
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods) {
14941492
PrettyStackTraceSelector stackTraceSelector("looking for", selector);
14951493
PrettyStackTraceDecl stackTraceDecl("...in", classDecl);
14961494
for (auto &loader : getImpl().ModuleLoaders) {
1495+
// Ignore the Clang importer if we've been asked for Swift-only results.
1496+
if (swiftOnly && loader.get() == getClangModuleLoader())
1497+
continue;
1498+
14971499
loader->loadObjCMethods(classDecl, selector, isInstanceMethod,
14981500
previousGeneration, methods);
14991501
}

lib/AST/Decl.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4274,9 +4274,6 @@ GetDestructorRequest::evaluate(Evaluator &evaluator, ClassDecl *CD) const {
42744274

42754275
// Mark DD as ObjC, as all dtors are.
42764276
DD->setIsObjC(ctx.LangOpts.EnableObjCInterop);
4277-
if (ctx.LangOpts.EnableObjCInterop)
4278-
CD->recordObjCMethod(DD, DD->getObjCSelector());
4279-
42804277
return DD;
42814278
}
42824279

lib/AST/Identifier.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,4 +271,6 @@ void ObjCSelector::dump() const {
271271
llvm::errs() << *this << "\n";
272272
}
273273

274-
274+
void swift::simple_display(llvm::raw_ostream &out, ObjCSelector selector) {
275+
out << "'" << selector << "'";
276+
}

lib/AST/NameLookup.cpp

Lines changed: 115 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -954,25 +954,56 @@ class swift::MemberLookupTable {
954954
}
955955
};
956956

957-
namespace {
957+
/// Class member lookup table, which is a member lookup table with a second
958+
/// table for lookup based on Objective-C selector.
959+
class ClassDecl::ObjCMethodLookupTable {
960+
using Key = std::pair<ObjCSelector, /*isInstanceMethod*/ char>;
961+
958962
/// Stores the set of Objective-C methods with a given selector within the
959963
/// Objective-C method lookup table.
960-
struct StoredObjCMethods {
964+
struct StoredMethods {
961965
/// The generation count at which this list was last updated.
962966
unsigned Generation = 0;
963967

964968
/// The set of methods with the given selector.
965969
llvm::TinyPtrVector<AbstractFunctionDecl *> Methods;
966970
};
967-
} // end anonymous namespace
968971

969-
/// Class member lookup table, which is a member lookup table with a second
970-
/// table for lookup based on Objective-C selector.
971-
class ClassDecl::ObjCMethodLookupTable
972-
: public llvm::DenseMap<std::pair<ObjCSelector, char>,
973-
StoredObjCMethods>
974-
{
972+
llvm::DenseMap<Key, StoredMethods> Table;
973+
llvm::DenseSet<Key> LazilyCompleteNames;
974+
975975
public:
976+
/// Create a new Obj-C method lookup table.
977+
explicit ObjCMethodLookupTable(ASTContext &ctx) {
978+
// Make sure the destructor is called when the AST context is torn down.
979+
ctx.addCleanup([this]() {
980+
this->~ObjCMethodLookupTable();
981+
});
982+
}
983+
984+
/// Returns \c true if the lookup table has a complete accounting of the
985+
/// given name.
986+
bool isLazilyComplete(ObjCSelector selector, bool isInstanceMethod) const {
987+
return LazilyCompleteNames.count({selector, isInstanceMethod});
988+
}
989+
990+
/// Mark a given lazily-loaded name as being complete.
991+
void markLazilyComplete(ObjCSelector selector, bool isInstanceMethod) {
992+
LazilyCompleteNames.insert({selector, isInstanceMethod});
993+
}
994+
995+
/// Clears the cache of lazily-complete names. This _must_ be called when
996+
/// new extensions with lazy members are added to the type, or lookups will
997+
/// return inconsistent or stale results.
998+
void clearLazilyCompleteCache() {
999+
LazilyCompleteNames.clear();
1000+
}
1001+
1002+
void addMember(Decl *member);
1003+
void addMembers(DeclRange members);
1004+
1005+
StoredMethods &operator[](Key key) { return Table[key]; }
1006+
9761007
// Only allow allocation of member lookup tables using the allocator in
9771008
// ASTContext or by doing a placement new.
9781009
void *operator new(size_t Bytes, ASTContext &C,
@@ -1045,13 +1076,22 @@ void MemberLookupTable::updateLookupTable(NominalTypeDecl *nominal) {
10451076
}
10461077

10471078
void NominalTypeDecl::addedExtension(ExtensionDecl *ext) {
1048-
if (!LookupTable) return;
1079+
ClassDecl::ObjCMethodLookupTable *ObjCLookupTable = nullptr;
1080+
if (auto *CD = dyn_cast<ClassDecl>(this))
1081+
ObjCLookupTable = CD->ObjCMethodLookup;
10491082

10501083
if (ext->hasLazyMembers()) {
1051-
LookupTable->addMembers(ext->getCurrentMembersWithoutLoading());
1052-
LookupTable->clearLazilyCompleteCache();
1084+
if (LookupTable) {
1085+
LookupTable->addMembers(ext->getCurrentMembersWithoutLoading());
1086+
LookupTable->clearLazilyCompleteCache();
1087+
}
1088+
if (ObjCLookupTable)
1089+
ObjCLookupTable->clearLazilyCompleteCache();
10531090
} else {
1054-
LookupTable->addMembers(ext->getMembers());
1091+
if (LookupTable)
1092+
LookupTable->addMembers(ext->getMembers());
1093+
if (ObjCLookupTable)
1094+
ObjCLookupTable->addMembers(ext->getMembers());
10551095
}
10561096
}
10571097

@@ -1297,63 +1337,80 @@ DirectLookupRequest::evaluate(Evaluator &evaluator,
12971337
includeAttrImplements);
12981338
}
12991339

1300-
void ClassDecl::createObjCMethodLookup() {
1301-
assert(!ObjCMethodLookup && "Already have an Objective-C member table");
1302-
auto &ctx = getASTContext();
1303-
ObjCMethodLookup = new (ctx) ObjCMethodLookupTable();
1340+
void ClassDecl::ObjCMethodLookupTable::addMember(Decl *member) {
1341+
if (auto *storage = dyn_cast<AbstractStorageDecl>(member)) {
1342+
// If this is an @objc var, make sure to add the necessary accessors.
1343+
if (storage->isObjC()) {
1344+
storage->visitEmittedAccessors(
1345+
[&](AccessorDecl *accessor) { addMember(accessor); });
1346+
}
1347+
return;
1348+
}
13041349

1305-
// Register a cleanup with the ASTContext to call the lookup table
1306-
// destructor.
1307-
ctx.addCleanup([this]() {
1308-
this->ObjCMethodLookup->~ObjCMethodLookupTable();
1309-
});
1350+
// We're only interested in tracking @objc functions.
1351+
auto *afd = dyn_cast<AbstractFunctionDecl>(member);
1352+
if (!afd || !afd->isObjC())
1353+
return;
1354+
1355+
auto &stored = Table[{afd->getObjCSelector(), afd->isObjCInstanceMethod()}];
1356+
stored.Methods.push_back(afd);
13101357
}
13111358

1312-
MutableArrayRef<AbstractFunctionDecl *>
1313-
ClassDecl::lookupDirect(ObjCSelector selector, bool isInstance) {
1314-
if (!ObjCMethodLookup) {
1315-
createObjCMethodLookup();
1316-
}
1359+
void ClassDecl::ObjCMethodLookupTable::addMembers(DeclRange members) {
1360+
for (auto *member : members)
1361+
addMember(member);
1362+
}
13171363

1318-
// If any modules have been loaded since we did the search last (or if we
1319-
// hadn't searched before), look in those modules, too.
1320-
auto &stored = (*ObjCMethodLookup)[{selector, isInstance}];
1321-
ASTContext &ctx = getASTContext();
1322-
if (ctx.getCurrentGeneration() > stored.Generation) {
1323-
ctx.loadObjCMethods(this, selector, isInstance, stored.Generation,
1324-
stored.Methods);
1325-
stored.Generation = ctx.getCurrentGeneration();
1364+
void ClassDecl::prepareObjCMethodLookup() {
1365+
if (ObjCMethodLookup) {
1366+
// Make sure the list of extensions is up-to-date, which may trigger the
1367+
// clearing of the lazily-complete cache.
1368+
(void)getExtensions();
1369+
return;
13261370
}
13271371

1328-
return { stored.Methods.begin(), stored.Methods.end() };
1329-
}
1372+
auto &ctx = getASTContext();
1373+
ObjCMethodLookup = new (ctx) ObjCMethodLookupTable(ctx);
13301374

1331-
void ClassDecl::recordObjCMethod(AbstractFunctionDecl *method,
1332-
ObjCSelector selector) {
1333-
if (!ObjCMethodLookup) {
1334-
createObjCMethodLookup();
1335-
}
1375+
// Pre-populate the table with any entries from the main module.
1376+
if (!hasLazyMembers())
1377+
ObjCMethodLookup->addMembers(getMembers());
13361378

1337-
// Record the method.
1338-
bool isInstanceMethod = method->isObjCInstanceMethod();
1339-
auto &vec = (*ObjCMethodLookup)[{selector, isInstanceMethod}].Methods;
1379+
for (auto *ext : getExtensions()) {
1380+
if (ext->wasDeserialized() || ext->hasClangNode())
1381+
continue;
13401382

1341-
// Check whether we have a duplicate. This only checks more than one
1342-
// element in ill-formed code, so the linear search is acceptable.
1343-
if (std::find(vec.begin(), vec.end(), method) != vec.end())
1344-
return;
1383+
ObjCMethodLookup->addMembers(ext->getMembers());
1384+
}
1385+
}
13451386

1346-
if (auto *sf = method->getParentSourceFile()) {
1347-
if (vec.size() == 1) {
1348-
// We have a conflict.
1349-
sf->ObjCMethodConflicts.push_back(std::make_tuple(this, selector,
1350-
isInstanceMethod));
1351-
} if (vec.empty()) {
1352-
sf->ObjCMethodList.push_back(method);
1353-
}
1387+
TinyPtrVector<AbstractFunctionDecl *>
1388+
ObjCMethodDirectLookupRequest::evaluate(Evaluator &evaluator, ClassDecl *CD,
1389+
ObjCSelector selector,
1390+
bool isInstance) const {
1391+
CD->prepareObjCMethodLookup();
1392+
auto &stored = (*CD->ObjCMethodLookup)[{selector, isInstance}];
1393+
1394+
// If we haven't seen this name before, or additional imported extensions have
1395+
// been bound since we last did a lookup, ask the module loaders to update the
1396+
// lookup table.
1397+
if (!CD->ObjCMethodLookup->isLazilyComplete(selector, isInstance)) {
1398+
auto &ctx = CD->getASTContext();
1399+
ctx.loadObjCMethods(CD, selector, isInstance, /*ignoreClang*/ false,
1400+
stored.Generation, stored.Methods);
1401+
stored.Generation = ctx.getCurrentGeneration();
1402+
CD->ObjCMethodLookup->markLazilyComplete(selector, isInstance);
13541403
}
1404+
return stored.Methods;
1405+
}
13551406

1356-
vec.push_back(method);
1407+
TinyPtrVector<AbstractFunctionDecl *>
1408+
ClassDecl::lookupDirect(ObjCSelector selector, bool isInstance) const {
1409+
auto &ctx = getASTContext();
1410+
auto *mutableThis = const_cast<ClassDecl *>(this);
1411+
return evaluateOrDefault(
1412+
ctx.evaluator,
1413+
ObjCMethodDirectLookupRequest{mutableThis, selector, isInstance}, {});
13571414
}
13581415

13591416
/// Determine whether the given declaration is an acceptable lookup

0 commit comments

Comments
 (0)