Skip to content

Commit 15a7a91

Browse files
committed
[CSOptimizer] Keep track of mismatches while evaluating candidates
1 parent 56b5158 commit 15a7a91

File tree

1 file changed

+45
-8
lines changed

1 file changed

+45
-8
lines changed

lib/Sema/CSOptimizer.cpp

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "swift/Sema/ConstraintGraph.h"
1818
#include "swift/Sema/ConstraintSystem.h"
19+
#include "llvm/ADT/BitVector.h"
1920
#include "llvm/ADT/DenseMap.h"
2021
#include "llvm/ADT/SmallVector.h"
2122
#include "llvm/ADT/TinyPtrVector.h"
@@ -231,20 +232,40 @@ static void determineBestChoicesInContext(
231232
if (paramType->is<FunctionType>())
232233
continue;
233234

234-
double argScore = 0.0;
235-
for (auto const &candidate : candidateArgumentTypes[i]) {
236-
auto candidateType = candidate.first;
235+
if (candidateArgumentTypes[i].empty())
236+
continue;
237+
238+
// The idea here is to match the parameter type against
239+
// all of the argument candidate types and pick the best
240+
// match (i.e. exact equality one).
241+
//
242+
// If none of the candidates match exactly and they are
243+
// all bound concrete types, we consider this is mismatch
244+
// at this parameter position and remove the overload choice
245+
// from consideration.
246+
247+
double bestCandidateScore = 0;
248+
llvm::BitVector mismatches(candidateArgumentTypes[i].size());
249+
250+
for (unsigned candidateIdx : indices(candidateArgumentTypes[i])) {
251+
Type candidateType;
252+
bool isLiteralDefault;
253+
254+
std::tie(candidateType, isLiteralDefault) =
255+
candidateArgumentTypes[i][candidateIdx];
237256

238257
// `inout` parameter accepts only l-value argument.
239-
if (paramFlags.isInOut() && !candidateType->is<LValueType>())
258+
if (paramFlags.isInOut() && !candidateType->is<LValueType>()) {
259+
mismatches.set(candidateIdx);
240260
continue;
261+
}
241262

242263
// The specifier only matters for `inout` check.
243264
candidateType = candidateType->getWithoutSpecifierType();
244265
// Exact match on one of the candidate bindings.
245266
if (candidateType->isEqual(paramType)) {
246-
argScore = std::max(
247-
argScore, /*fromLiteral=*/candidate.second ? 0.3 : 1.0);
267+
bestCandidateScore =
268+
std::max(bestCandidateScore, isLiteralDefault ? 0.3 : 1.0);
248269
continue;
249270
}
250271

@@ -253,14 +274,30 @@ static void determineBestChoicesInContext(
253274
// and expect a particular `Scalar` if it's known.
254275
if (isSIMDType(candidateType) &&
255276
isArithmeticOperatorOnSIMDProtocol(decl)) {
256-
argScore = std::max(argScore, 1.0);
277+
bestCandidateScore = 1.0;
257278
continue;
258279
}
280+
281+
// Only established arguments could be considered mismatches,
282+
// literal default types should be regarded as holes if they
283+
// didn't match.
284+
if (!isLiteralDefault && !candidateType->hasTypeVariable())
285+
mismatches.set(candidateIdx);
286+
}
287+
288+
// If none of the candidates for this parameter matched, let's
289+
// remove this overload from consideration.
290+
if (mismatches.all()) {
291+
score = -1;
292+
break;
259293
}
260294

261-
score += argScore;
295+
score += bestCandidateScore;
262296
}
263297

298+
if (score == -1)
299+
return;
300+
264301
// Average the score to avoid disfavoring disjunctions with fewer
265302
// parameters.
266303
score /= overloadType->getNumParams();

0 commit comments

Comments
 (0)