Skip to content

Commit ea5a42d

Browse files
authored
Merge pull request #9963 from xedin/rdar-32204609
[ConstraintSolver] Skip generic overloads only if non-generic choices produce higher score solutions
2 parents c1c4f52 + 5998cd6 commit ea5a42d

File tree

6 files changed

+46
-16
lines changed

6 files changed

+46
-16
lines changed

lib/Sema/CSRanking.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ void ConstraintSystem::increaseScore(ScoreKind kind, unsigned value) {
8383
case SK_KeyPathSubscript:
8484
log << "key path subscript";
8585
break;
86+
87+
case SK_StringToPointerConversion:
88+
log << "string-to-pointer conversion";
89+
break;
8690
}
8791
log << ")\n";
8892
}

lib/Sema/CSSimplify.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4397,6 +4397,8 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
43974397
// If we haven't resolved the element type, generate constraints.
43984398
if (baseType2->isTypeVariableOrMember()) {
43994399
if (flags.contains(TMF_GenerateConstraints)) {
4400+
increaseScore(SK_StringToPointerConversion);
4401+
44004402
auto int8Con = Constraint::create(*this, ConstraintKind::Bind,
44014403
baseType2, TC.getInt8Type(DC),
44024404
getConstraintLocator(locator));
@@ -4418,6 +4420,8 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
44184420
if (!isStringCompatiblePointerBaseType(TC, DC, baseType2)) {
44194421
return SolutionKind::Error;
44204422
}
4423+
4424+
increaseScore(SK_StringToPointerConversion);
44214425
return SolutionKind::Solved;
44224426
}
44234427

lib/Sema/CSSolver.cpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2480,8 +2480,9 @@ bool ConstraintSystem::solveSimplified(
24802480
auto afterDisjunction = InactiveConstraints.erase(disjunction);
24812481
CG.removeConstraint(disjunction);
24822482

2483+
Score initialScore = CurrentScore;
24832484
Optional<DisjunctionChoice> lastSolvedChoice;
2484-
Optional<DisjunctionChoice> firstNonGenericOperatorSolution;
2485+
Optional<Score> bestNonGenericScore;
24852486

24862487
++solverState->NumDisjunctions;
24872488
auto constraints = disjunction->getNestedConstraints();
@@ -2507,9 +2508,13 @@ bool ConstraintSystem::solveSimplified(
25072508
// already have a solution involving non-generic operators,
25082509
// but continue looking for a better non-generic operator
25092510
// solution.
2510-
if (firstNonGenericOperatorSolution &&
2511-
currentChoice.isGenericOperatorOrUnavailable())
2512-
continue;
2511+
if (bestNonGenericScore && currentChoice.isGenericOperatorOrUnavailable()) {
2512+
// If non-generic solution increased the score by applying any
2513+
// fixes or restrictions to the solution, let's not skip generic
2514+
// overloads because they could produce a better solution.
2515+
if (bestNonGenericScore <= initialScore)
2516+
continue;
2517+
}
25132518

25142519
// We already have a solution; check whether we should
25152520
// short-circuit the disjunction.
@@ -2542,11 +2547,12 @@ bool ConstraintSystem::solveSimplified(
25422547
DisjunctionChoices.push_back({locator, index});
25432548
}
25442549

2545-
if (currentChoice.solve(solutions, allowFreeTypeVariables)) {
2546-
if (!firstNonGenericOperatorSolution &&
2547-
!currentChoice.isGenericOperatorOrUnavailable() &&
2548-
currentChoice.isSymmetricOperator())
2549-
firstNonGenericOperatorSolution = currentChoice;
2550+
if (auto score = currentChoice.solve(solutions, allowFreeTypeVariables)) {
2551+
if (!currentChoice.isGenericOperatorOrUnavailable() &&
2552+
currentChoice.isSymmetricOperator()) {
2553+
if (!bestNonGenericScore || score < bestNonGenericScore)
2554+
bestNonGenericScore = score;
2555+
}
25502556

25512557
lastSolvedChoice = currentChoice;
25522558

@@ -2578,10 +2584,12 @@ bool ConstraintSystem::solveSimplified(
25782584
return tooComplex || !lastSolvedChoice;
25792585
}
25802586

2581-
bool DisjunctionChoice::solve(SmallVectorImpl<Solution> &solutions,
2582-
FreeTypeVariableBinding allowFreeTypeVariables) {
2587+
Optional<Score>
2588+
DisjunctionChoice::solve(SmallVectorImpl<Solution> &solutions,
2589+
FreeTypeVariableBinding allowFreeTypeVariables) {
25832590
CS->simplifyDisjunctionChoice(Choice);
2584-
return !CS->solveRec(solutions, allowFreeTypeVariables);
2591+
bool failed = CS->solveRec(solutions, allowFreeTypeVariables);
2592+
return failed ? None : Optional<Score>(CS->CurrentScore);
25852593
}
25862594

25872595
bool DisjunctionChoice::isGenericOperatorOrUnavailable() const {

lib/Sema/ConstraintSystem.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -416,8 +416,10 @@ enum ScoreKind {
416416
SK_EmptyExistentialConversion,
417417
/// A key path application subscript.
418418
SK_KeyPathSubscript,
419-
420-
SK_LastScoreKind = SK_KeyPathSubscript,
419+
// A conversion from a string to a pointer.
420+
SK_StringToPointerConversion,
421+
422+
SK_LastScoreKind = SK_StringToPointerConversion,
421423
};
422424

423425
/// The number of score kinds.
@@ -2671,8 +2673,8 @@ class DisjunctionChoice {
26712673
bool isSymmetricOperator() const;
26722674

26732675
/// \brief Apply given choice to the system and try to solve it.
2674-
bool solve(SmallVectorImpl<Solution> &solutions,
2675-
FreeTypeVariableBinding allowFreeTypeVariables);
2676+
Optional<Score> solve(SmallVectorImpl<Solution> &solutions,
2677+
FreeTypeVariableBinding allowFreeTypeVariables);
26762678

26772679
private:
26782680
static ValueDecl *getOperatorDecl(Constraint *constraint) {

test/Constraints/overload.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,4 @@ func curry<F, S, T, R>(_ f: @escaping (F, S, T) -> R) -> (F) -> (S) -> (T) -> R
222222
// Ensure that we consider these unambiguous
223223
let _ = curry(+)(1)
224224
let _ = [0].reduce(0, +)
225+
let _ = curry(+)("string vs. pointer")
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: %target-build-swift %s -o %t/a.out
4+
// RUN: %target-run %t/a.out
5+
6+
// REQUIRES: executable_test
7+
8+
let x: Int! = nil
9+
let y: Int! = 1
10+
11+
print(x == y)

0 commit comments

Comments
 (0)