Skip to content

Commit a094c3e

Browse files
committed
[CSOptimizer] Keep track of mismatches while evaluating candidates
1 parent c2f7451 commit a094c3e

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,45 @@ 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+
// If one of the candidates matched exactly there is no reason
252+
// to continue checking.
253+
if (bestCandidateScore == 1)
254+
break;
255+
256+
Type candidateType;
257+
bool isLiteralDefault;
258+
259+
std::tie(candidateType, isLiteralDefault) =
260+
candidateArgumentTypes[i][candidateIdx];
237261

238262
// `inout` parameter accepts only l-value argument.
239-
if (paramFlags.isInOut() && !candidateType->is<LValueType>())
263+
if (paramFlags.isInOut() && !candidateType->is<LValueType>()) {
264+
mismatches.set(candidateIdx);
240265
continue;
266+
}
241267

242268
// The specifier only matters for `inout` check.
243269
candidateType = candidateType->getWithoutSpecifierType();
244270
// Exact match on one of the candidate bindings.
245271
if (candidateType->isEqual(paramType)) {
246-
argScore = std::max(
247-
argScore, /*fromLiteral=*/candidate.second ? 0.3 : 1.0);
272+
bestCandidateScore =
273+
std::max(bestCandidateScore, isLiteralDefault ? 0.3 : 1.0);
248274
continue;
249275
}
250276

@@ -253,12 +279,23 @@ static void determineBestChoicesInContext(
253279
// and expect a particular `Scalar` if it's known.
254280
if (isSIMDType(candidateType) &&
255281
isArithmeticOperatorOnSIMDProtocol(decl)) {
256-
argScore = std::max(argScore, 1.0);
282+
bestCandidateScore = 1.0;
257283
continue;
258284
}
285+
286+
// Only established arguments could be considered mismatches,
287+
// literal default types should be regarded as holes if they
288+
// didn't match.
289+
if (!isLiteralDefault && !candidateType->hasTypeVariable())
290+
mismatches.set(candidateIdx);
259291
}
260292

261-
score += argScore;
293+
// If none of the candidates for this parameter matched, let's
294+
// drop this overload from any further consideration.
295+
if (mismatches.all())
296+
return;
297+
298+
score += bestCandidateScore;
262299
}
263300

264301
// Average the score to avoid disfavoring disjunctions with fewer

0 commit comments

Comments
 (0)