Skip to content

Commit 9fb7314

Browse files
committed
[CSOptimizer] Limit "old" behavior compatibility to unlabeled unary arguments
`favorMatchingOverloadExprs` used `getUnlabeledUnaryExpr` and we need to mimic that exactly because there is code that relies on this behavior now.
1 parent ff8663f commit 9fb7314

File tree

2 files changed

+33
-11
lines changed

2 files changed

+33
-11
lines changed

lib/Sema/CSOptimizer.cpp

+22-11
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,15 @@ static OverloadedDeclRefExpr *isOverloadedDeclRef(Constraint *disjunction) {
181181
return nullptr;
182182
}
183183

184+
static unsigned numOverloadChoicesMatchingOnArity(OverloadedDeclRefExpr *ODRE,
185+
ArgumentList *arguments) {
186+
return llvm::count_if(ODRE->getDecls(), [&arguments](auto *choice) {
187+
if (auto *paramList = getParameterList(choice))
188+
return arguments->size() == paramList->size();
189+
return false;
190+
});
191+
}
192+
184193
/// This maintains an "old hack" behavior where overloads of some
185194
/// `OverloadedDeclRef` calls were favored purely based on number of
186195
/// argument and (non-defaulted) parameters matching.
@@ -191,11 +200,7 @@ static void findFavoredChoicesBasedOnArity(
191200
if (!ODRE)
192201
return;
193202

194-
if (llvm::count_if(ODRE->getDecls(), [&argumentList](auto *choice) {
195-
if (auto *paramList = getParameterList(choice))
196-
return argumentList->size() == paramList->size();
197-
return false;
198-
}) > 1)
203+
if (numOverloadChoicesMatchingOnArity(ODRE, argumentList) > 1)
199204
return;
200205

201206
auto isVariadicGenericOverload = [&](ValueDecl *choice) {
@@ -631,7 +636,16 @@ static Constraint *determineBestChoicesInContext(
631636
double bestScore = 0.0;
632637
SmallVector<std::pair<Constraint *, double>, 2> favoredChoices;
633638

634-
bool isOverloadedDeclRefDisjunction = isOverloadedDeclRef(disjunction);
639+
// Preserves old behavior where, for unary calls, the solver
640+
// would not consider choices that didn't match on the number
641+
// of parameters (regardless of defaults) and only exact
642+
// matches were favored.
643+
bool preserveFavoringOfUnlabeledUnaryArgument = false;
644+
if (argumentList->isUnlabeledUnary()) {
645+
auto ODRE = isOverloadedDeclRef(disjunction);
646+
preserveFavoringOfUnlabeledUnaryArgument =
647+
!ODRE || numOverloadChoicesMatchingOnArity(ODRE, argumentList) < 2;
648+
}
635649

636650
forEachDisjunctionChoice(
637651
cs, disjunction,
@@ -654,11 +668,8 @@ static Constraint *determineBestChoicesInContext(
654668
// matches to filter out non-default literal bindings which otherwise
655669
// could cause "over-favoring".
656670
bool favorExactMatchesOnly = onlyLiteralCandidates;
657-
// Preserves old behavior where for unary calls to members
658-
// the solver would not consider choices that didn't match on
659-
// the number of parameters (regardless of defaults) and only
660-
// exact matches were favored.
661-
if (!isOverloadedDeclRefDisjunction && argumentList->size() == 1) {
671+
672+
if (preserveFavoringOfUnlabeledUnaryArgument) {
662673
// Old behavior completely disregarded the fact that some of
663674
// the parameters could be defaulted.
664675
if (overloadType->getNumParams() != 1)

test/Constraints/old_hack_related_ambiguities.swift

+11
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@ do {
4343
do {
4444
struct S {
4545
let n: Int
46+
47+
func test(v: String) -> Int { }
48+
func test(v: String, flag: Bool = false) -> Int? { }
49+
50+
51+
func verify(v: String) -> Int? {
52+
guard let _ = test(v: v) else { // Ok
53+
return nil
54+
}
55+
return 0
56+
}
4657
}
4758

4859
func f(_: String, _ p: Bool = false) -> S? {

0 commit comments

Comments
 (0)