Skip to content

Commit 1bc7a1e

Browse files
committed
[ConstraintSolver] Skip generic overloads only if non-generic choices produce higher score solutions
Restrict skipping of the generic overloads only to the situations when non-generic solution doesn't have any restrictions/fixes, because there is a possibility that generic overload could produce a better solution. Resolves: rdar://problem/32204609.
1 parent 0a0585c commit 1bc7a1e

File tree

3 files changed

+33
-14
lines changed

3 files changed

+33
-14
lines changed

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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2671,8 +2671,8 @@ class DisjunctionChoice {
26712671
bool isSymmetricOperator() const;
26722672

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

26772677
private:
26782678
static ValueDecl *getOperatorDecl(Constraint *constraint) {
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)