Skip to content

Commit 9445a9f

Browse files
committed
[CSOptimizer] Decrease an operator argument score only if requires optional injection
This makes sure that optional and non-optional types are ranked uniformly when matched against a generic parameter type that could accept either of them. This is a more general fix for #83365
1 parent 597aaba commit 9445a9f

File tree

1 file changed

+14
-21
lines changed

1 file changed

+14
-21
lines changed

lib/Sema/CSOptimizer.cpp

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -970,8 +970,6 @@ static void determineBestChoicesInContext(
970970

971971
bool hasArgumentCandidates = false;
972972
bool isOperator = isOperatorDisjunction(disjunction);
973-
bool isNilCoalescingOperator =
974-
isOperator && isOperatorNamed(disjunction, "??");
975973

976974
for (unsigned i = 0, n = argFuncType->getNumParams(); i != n; ++i) {
977975
const auto &param = argFuncType->getParams()[i];
@@ -1341,17 +1339,26 @@ static void determineBestChoicesInContext(
13411339
paramType = paramType->lookThroughAllOptionalTypes(paramOptionals);
13421340

13431341
if (!candidateOptionals.empty() || !paramOptionals.empty()) {
1342+
auto requiresOptionalInjection = [&]() {
1343+
return paramOptionals.size() > candidateOptionals.size();
1344+
};
1345+
13441346
// Can match i.e. Int? to Int or T to Int?
13451347
if ((paramOptionals.empty() &&
13461348
paramType->is<GenericTypeParamType>()) ||
13471349
paramOptionals.size() >= candidateOptionals.size()) {
13481350
auto score = scoreCandidateMatch(genericSig, choice, candidateType,
13491351
paramType, options);
1350-
// Injection lowers the score slightly to comply with
1351-
// old behavior where exact matches on operator parameter
1352-
// types were always preferred.
1353-
return score > 0 && choice->isOperator() ? score.value() - 0.1
1354-
: score;
1352+
1353+
if (score > 0) {
1354+
// Injection lowers the score slightly to comply with
1355+
// old behavior where exact matches on operator parameter
1356+
// types were always preferred.
1357+
if (choice->isOperator() && requiresOptionalInjection())
1358+
return score.value() - 0.1;
1359+
}
1360+
1361+
return score;
13551362
}
13561363

13571364
// Optionality mismatch.
@@ -1605,20 +1612,6 @@ static void determineBestChoicesInContext(
16051612
double bestCandidateScore = 0;
16061613
llvm::BitVector mismatches(argumentCandidates[argIdx].size());
16071614

1608-
// `??` is overloaded on optionality of the second parameter,
1609-
// prevent ranking the argument candidates for this parameter
1610-
// if there are candidates that come from failable initializer
1611-
// overloads because non-optional candidates are always going
1612-
// to be better and that can skew the selection.
1613-
if (isNilCoalescingOperator && argIdx == 1) {
1614-
if (llvm::any_of(argumentCandidates[argIdx],
1615-
[](const auto &candidate) {
1616-
return candidate.fromInitializerCall &&
1617-
candidate.type->getOptionalObjectType();
1618-
}))
1619-
continue;
1620-
}
1621-
16221615
for (unsigned candidateIdx :
16231616
indices(argumentCandidates[argIdx])) {
16241617
// If one of the candidates matched exactly there is no reason

0 commit comments

Comments
 (0)