Skip to content

Commit 07ce01d

Browse files
committed
AST: Replace ASTContext's ObjCMethodConflicts list with a per-SourceFile list
1 parent 0fae7e8 commit 07ce01d

File tree

4 files changed

+38
-134
lines changed

4 files changed

+38
-134
lines changed

include/swift/AST/ASTContext.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -846,11 +846,6 @@ class ASTContext final {
846846
/// as overrides in Swift.
847847
bool diagnoseUnintendedObjCMethodOverrides(SourceFile &sf);
848848

849-
/// Note that there is a conflict between different definitions that
850-
/// produce the same Objective-C method.
851-
void recordObjCMethodConflict(ClassDecl *classDecl, ObjCSelector selector,
852-
bool isInstance);
853-
854849
/// Diagnose all conflicts between members that have the same
855850
/// Objective-C selector in the same class.
856851
///

include/swift/AST/Module.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,11 @@ class SourceFile final : public FileUnit {
10391039
/// unsatisfied, which might conflict with other Objective-C methods.
10401040
std::vector<ObjCUnsatisfiedOptReq> ObjCUnsatisfiedOptReqs;
10411041

1042+
using ObjCMethodConflict = std::tuple<ClassDecl *, ObjCSelector, bool>;
1043+
1044+
/// List of Objective-C member conflicts we have found during type checking.
1045+
std::vector<ObjCMethodConflict> ObjCMethodConflicts;
1046+
10421047
template <typename T>
10431048
using OperatorMap = llvm::DenseMap<Identifier,llvm::PointerIntPair<T,1,bool>>;
10441049

lib/AST/ASTContext.cpp

Lines changed: 24 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,6 @@ llvm::StringRef swift::getProtocolName(KnownProtocolKind kind) {
8888
}
8989

9090
namespace {
91-
typedef std::tuple<ClassDecl *, ObjCSelector, bool> ObjCMethodConflict;
92-
9391
enum class SearchPathKind : uint8_t {
9492
Import = 1 << 0,
9593
Framework = 1 << 1
@@ -375,9 +373,6 @@ FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL)
375373
llvm::FoldingSet<DeclName::CompoundDeclName> CompoundNames;
376374
llvm::DenseMap<UUID, OpenedArchetypeType *> OpenedExistentialArchetypes;
377375

378-
/// List of Objective-C member conflicts we have found during type checking.
379-
std::vector<ObjCMethodConflict> ObjCMethodConflicts;
380-
381376
/// A cache of information about whether particular nominal types
382377
/// are representable in a foreign language.
383378
llvm::DenseMap<NominalTypeDecl *, ForeignRepresentationInfo>
@@ -2070,40 +2065,6 @@ namespace {
20702065
return lhs->getFullName() < rhs->getFullName();
20712066
}
20722067
};
2073-
2074-
/// Produce a deterministic ordering of the given declarations with
2075-
/// a bias that favors declarations in the given source file and
2076-
/// members of a class.
2077-
class OrderDeclarationsWithSourceFileAndClassBias {
2078-
SourceManager &SrcMgr;
2079-
SourceFile &SF;
2080-
2081-
public:
2082-
OrderDeclarationsWithSourceFileAndClassBias(SourceManager &srcMgr,
2083-
SourceFile &sf)
2084-
: SrcMgr(srcMgr), SF(sf) { }
2085-
2086-
bool operator()(ValueDecl *lhs, ValueDecl *rhs) const {
2087-
// Check whether the declarations are in a class.
2088-
bool lhsInClass = isa<ClassDecl>(lhs->getDeclContext());
2089-
bool rhsInClass = isa<ClassDecl>(rhs->getDeclContext());
2090-
if (lhsInClass != rhsInClass)
2091-
return lhsInClass;
2092-
2093-
// If the two declarations are in different source files, and one of those
2094-
// source files is the source file we're biasing toward, prefer that
2095-
// declaration.
2096-
SourceFile *lhsSF = lhs->getDeclContext()->getParentSourceFile();
2097-
SourceFile *rhsSF = rhs->getDeclContext()->getParentSourceFile();
2098-
if (lhsSF != rhsSF) {
2099-
if (lhsSF == &SF) return true;
2100-
if (rhsSF == &SF) return false;
2101-
}
2102-
2103-
// Fall back to the normal deterministic ordering.
2104-
return OrderDeclarations(SrcMgr)(lhs, rhs);
2105-
}
2106-
};
21072068
} // end anonymous namespace
21082069

21092070
/// Compute the information used to describe an Objective-C redeclaration.
@@ -2478,16 +2439,9 @@ bool ASTContext::diagnoseUnintendedObjCMethodOverrides(SourceFile &sf) {
24782439
return diagnosedAny;
24792440
}
24802441

2481-
void ASTContext::recordObjCMethodConflict(ClassDecl *classDecl,
2482-
ObjCSelector selector,
2483-
bool isInstance) {
2484-
getImpl().ObjCMethodConflicts.push_back(std::make_tuple(classDecl, selector,
2485-
isInstance));
2486-
}
2487-
24882442
/// Retrieve the source file for the given Objective-C member conflict.
24892443
static MutableArrayRef<AbstractFunctionDecl *>
2490-
getObjCMethodConflictDecls(const ObjCMethodConflict &conflict) {
2444+
getObjCMethodConflictDecls(const SourceFile::ObjCMethodConflict &conflict) {
24912445
ClassDecl *classDecl = std::get<0>(conflict);
24922446
ObjCSelector selector = std::get<1>(conflict);
24932447
bool isInstanceMethod = std::get<2>(conflict);
@@ -2526,80 +2480,27 @@ static void removeValidObjCConflictingMethods(
25262480
methods = methods.slice(0, newEnd - methods.begin());
25272481
}
25282482

2529-
/// Determine whether we should associate a conflict among the given
2530-
/// set of methods with the specified source file.
2531-
static bool shouldAssociateConflictWithSourceFile(
2532-
SourceFile &sf,
2533-
ArrayRef<AbstractFunctionDecl *> methods) {
2534-
bool anyInSourceFile = false;
2535-
bool anyInOtherSourceFile = false;
2536-
bool anyClassMethodsInSourceFile = false;
2537-
for (auto method : methods) {
2538-
// Skip methods in the class itself; we want to only diagnose
2539-
// those if there is a conflict within that file.
2540-
if (isa<ClassDecl>(method->getDeclContext())) {
2541-
if (method->getParentSourceFile() == &sf)
2542-
anyClassMethodsInSourceFile = true;
2543-
continue;
2544-
}
2545-
2546-
if (method->getParentSourceFile() == &sf)
2547-
anyInSourceFile = true;
2548-
else
2549-
anyInOtherSourceFile = true;
2550-
}
2551-
2552-
return anyInSourceFile ||
2553-
(!anyInOtherSourceFile && anyClassMethodsInSourceFile);
2554-
}
2555-
25562483
bool ASTContext::diagnoseObjCMethodConflicts(SourceFile &sf) {
25572484
// If there were no conflicts, we're done.
2558-
if (getImpl().ObjCMethodConflicts.empty())
2485+
if (sf.ObjCMethodConflicts.empty())
25592486
return false;
25602487

2561-
// Partition the set of conflicts to put the conflicts that involve
2562-
// this source file at the end.
2563-
auto firstLocalConflict
2564-
= std::partition(getImpl().ObjCMethodConflicts.begin(),
2565-
getImpl().ObjCMethodConflicts.end(),
2566-
[&](const ObjCMethodConflict &conflict) -> bool {
2567-
auto decls = getObjCMethodConflictDecls(conflict);
2568-
if (shouldAssociateConflictWithSourceFile(sf, decls)) {
2569-
// It's in this source file. Sort the conflict
2570-
// declarations. We'll use this later.
2571-
std::sort(
2572-
decls.begin(), decls.end(),
2573-
OrderDeclarationsWithSourceFileAndClassBias(
2574-
SourceMgr, sf));
2575-
2576-
return false;
2577-
}
2578-
2579-
return true;
2580-
});
2581-
2582-
// If there were no local conflicts, we're done.
2583-
unsigned numLocalConflicts
2584-
= getImpl().ObjCMethodConflicts.end() - firstLocalConflict;
2585-
if (numLocalConflicts == 0)
2586-
return false;
2488+
OrderDeclarations ordering(SourceMgr);
25872489

25882490
// Sort the set of conflicts so we get a deterministic order for
25892491
// diagnostics. We use the first conflicting declaration in each set to
25902492
// perform the sort.
2591-
MutableArrayRef<ObjCMethodConflict> localConflicts(&*firstLocalConflict,
2592-
numLocalConflicts);
2493+
auto localConflicts = sf.ObjCMethodConflicts;
25932494
std::sort(localConflicts.begin(), localConflicts.end(),
2594-
[&](const ObjCMethodConflict &lhs, const ObjCMethodConflict &rhs) {
2595-
OrderDeclarations ordering(SourceMgr);
2495+
[&](const SourceFile::ObjCMethodConflict &lhs,
2496+
const SourceFile::ObjCMethodConflict &rhs) {
25962497
return ordering(getObjCMethodConflictDecls(lhs)[1],
25972498
getObjCMethodConflictDecls(rhs)[1]);
25982499
});
25992500

26002501
// Diagnose each conflict.
26012502
bool anyConflicts = false;
2602-
for (const ObjCMethodConflict &conflict : localConflicts) {
2503+
for (const auto &conflict : localConflicts) {
26032504
ObjCSelector selector = std::get<1>(conflict);
26042505

26052506
auto methods = getObjCMethodConflictDecls(conflict);
@@ -2612,13 +2513,22 @@ bool ASTContext::diagnoseObjCMethodConflicts(SourceFile &sf) {
26122513
// Diagnose the conflict.
26132514
anyConflicts = true;
26142515

2615-
// If the first method has a valid source location but the first conflicting
2616-
// declaration does not, swap them so the primary diagnostic has a useful
2617-
// source location.
2618-
if (methods[1]->getLoc().isInvalid() && methods[0]->getLoc().isValid()) {
2516+
// If the first method is in an extension and the second is not, swap them
2517+
// so the primary diagnostic is on the extension method.
2518+
if (isa<ExtensionDecl>(methods[0]->getDeclContext()) &&
2519+
!isa<ExtensionDecl>(methods[1]->getDeclContext())) {
2520+
std::swap(methods[0], methods[1]);
2521+
2522+
// Within a source file, use our canonical ordering.
2523+
} else if (methods[0]->getParentSourceFile() ==
2524+
methods[1]->getParentSourceFile() &&
2525+
!ordering(methods[0], methods[1])) {
26192526
std::swap(methods[0], methods[1]);
26202527
}
26212528

2529+
// Otherwise, fall back to the order in which the declarations were type
2530+
// checked.
2531+
26222532
auto originalMethod = methods.front();
26232533
auto conflictingMethods = methods.slice(1);
26242534

@@ -2649,10 +2559,6 @@ bool ASTContext::diagnoseObjCMethodConflicts(SourceFile &sf) {
26492559
}
26502560
}
26512561

2652-
// Erase the local conflicts from the list of conflicts.
2653-
getImpl().ObjCMethodConflicts.erase(firstLocalConflict,
2654-
getImpl().ObjCMethodConflicts.end());
2655-
26562562
return anyConflicts;
26572563
}
26582564

@@ -2667,15 +2573,15 @@ static SourceLoc getDeclContextLoc(DeclContext *dc) {
26672573

26682574
bool ASTContext::diagnoseObjCUnsatisfiedOptReqConflicts(SourceFile &sf) {
26692575
// If there are no unsatisfied, optional @objc requirements, we're done.
2670-
if (sf->ObjCUnsatisfiedOptReqs.empty())
2576+
if (sf.ObjCUnsatisfiedOptReqs.empty())
26712577
return false;
26722578

26732579
// Sort the set of local unsatisfied requirements, so we get a
26742580
// deterministic order for diagnostics.
2675-
auto &localReqs = sf->ObjCUnsatisfiedOptReqs;
2581+
auto &localReqs = sf.ObjCUnsatisfiedOptReqs;
26762582
std::sort(localReqs.begin(), localReqs.end(),
2677-
[&](const ObjCUnsatisfiedOptReq &lhs,
2678-
const ObjCUnsatisfiedOptReq &rhs) -> bool {
2583+
[&](const SourceFile::ObjCUnsatisfiedOptReq &lhs,
2584+
const SourceFile::ObjCUnsatisfiedOptReq &rhs) -> bool {
26792585
return SourceMgr.isBeforeInBuffer(getDeclContextLoc(lhs.first),
26802586
getDeclContextLoc(rhs.first));
26812587
});

lib/AST/NameLookup.cpp

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,21 +1257,19 @@ void ClassDecl::recordObjCMethod(AbstractFunctionDecl *method,
12571257
bool isInstanceMethod = method->isObjCInstanceMethod();
12581258
auto &vec = (*ObjCMethodLookup)[{selector, isInstanceMethod}].Methods;
12591259

1260-
// In a non-empty vector, we could have duplicates or conflicts.
1261-
if (!vec.empty()) {
1262-
// Check whether we have a duplicate. This only checks more than one
1263-
// element in ill-formed code, so the linear search is acceptable.
1264-
if (std::find(vec.begin(), vec.end(), method) != vec.end())
1265-
return;
1260+
// Check whether we have a duplicate. This only checks more than one
1261+
// element in ill-formed code, so the linear search is acceptable.
1262+
if (std::find(vec.begin(), vec.end(), method) != vec.end())
1263+
return;
12661264

1265+
if (auto *sf = method->getParentSourceFile()) {
12671266
if (vec.size() == 1) {
12681267
// We have a conflict.
1269-
getASTContext().recordObjCMethodConflict(this, selector,
1270-
isInstanceMethod);
1271-
}
1272-
} else {
1273-
if (auto *sf = method->getParentSourceFile())
1268+
sf->ObjCMethodConflicts.push_back(std::make_tuple(this, selector,
1269+
isInstanceMethod));
1270+
} if (vec.empty()) {
12741271
sf->ObjCMethodList.push_back(method);
1272+
}
12751273
}
12761274

12771275
vec.push_back(method);

0 commit comments

Comments
 (0)