Skip to content

Commit 1c2c111

Browse files
committed
[NFC] Correct selector conflict sorting rules
When two members have the same ObjC selector, there’s a test used to make sure that we’re “giving” the selector to the more “authoritative” of the two. However, its logic is not symmetrical, which I suspect could cause misbehavior in some edge cases. This change formalizes the logic in a way that eliminates the asymmetry.
1 parent 3911542 commit 1c2c111

File tree

1 file changed

+29
-14
lines changed

1 file changed

+29
-14
lines changed

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2461,22 +2461,37 @@ bool swift::diagnoseObjCMethodConflicts(SourceFile &sf) {
24612461
// Diagnose the conflict.
24622462
anyConflicts = true;
24632463

2464-
// If the first method is in an extension and the second is not, swap them
2465-
// so the primary diagnostic is on the extension method.
2466-
MutableArrayRef<AbstractFunctionDecl *> methodsRef(methods);
2467-
if (isa<ExtensionDecl>(methods[0]->getDeclContext()) &&
2468-
!isa<ExtensionDecl>(methods[1]->getDeclContext())) {
2469-
std::swap(methodsRef[0], methodsRef[1]);
2464+
/// If true, \p a has a "weaker" claim on the selector than \p b, and the
2465+
/// conflict diagnostic should appear on \p a instead of \p b.
2466+
auto areBackwards =
2467+
[&](AbstractFunctionDecl *a, AbstractFunctionDecl *b) -> bool {
2468+
#define RULE(aCriterion, bCriterion) do { \
2469+
bool _aCriterion = (aCriterion), _bCriterion = (bCriterion); \
2470+
if (!_aCriterion && _bCriterion) \
2471+
return true; \
2472+
if (_aCriterion && !_bCriterion) \
2473+
return false; \
2474+
} while (0)
2475+
2476+
// Is one of these from the main declaration?
2477+
RULE(!isa<ExtensionDecl>(a->getDeclContext()),
2478+
!isa<ExtensionDecl>(b->getDeclContext()));
2479+
2480+
// Are these from different source files? If so, fall back to the order in
2481+
// which the declarations were type checked.
2482+
// FIXME: This is gross and nondeterministic.
2483+
if (a->getParentSourceFile() != b->getParentSourceFile())
2484+
return false;
24702485

2471-
// Within a source file, use our canonical ordering.
2472-
} else if (methods[0]->getParentSourceFile() ==
2473-
methods[1]->getParentSourceFile() &&
2474-
!ordering(methods[0], methods[1])) {
2475-
std::swap(methodsRef[0], methodsRef[1]);
2476-
}
2486+
// Handle them in source order.
2487+
return !ordering(a, b);
24772488

2478-
// Otherwise, fall back to the order in which the declarations were type
2479-
// checked.
2489+
#undef RULE
2490+
};
2491+
2492+
MutableArrayRef<AbstractFunctionDecl *> methodsRef(methods);
2493+
if (areBackwards(methods[0], methods[1]))
2494+
std::swap(methodsRef[0], methodsRef[1]);
24802495

24812496
auto originalMethod = methods.front();
24822497
auto conflictingMethods = methodsRef.slice(1);

0 commit comments

Comments
 (0)