Skip to content

Commit

Permalink
[ConstraintSolver] Skip generic overloads only if non-generic choices…
Browse files Browse the repository at this point in the history
… 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.
  • Loading branch information
xedin committed Jun 1, 2017
1 parent 0a0585c commit 1bc7a1e
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 14 deletions.
32 changes: 20 additions & 12 deletions lib/Sema/CSSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2480,8 +2480,9 @@ bool ConstraintSystem::solveSimplified(
auto afterDisjunction = InactiveConstraints.erase(disjunction);
CG.removeConstraint(disjunction);

Score initialScore = CurrentScore;
Optional<DisjunctionChoice> lastSolvedChoice;
Optional<DisjunctionChoice> firstNonGenericOperatorSolution;
Optional<Score> bestNonGenericScore;

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

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

if (currentChoice.solve(solutions, allowFreeTypeVariables)) {
if (!firstNonGenericOperatorSolution &&
!currentChoice.isGenericOperatorOrUnavailable() &&
currentChoice.isSymmetricOperator())
firstNonGenericOperatorSolution = currentChoice;
if (auto score = currentChoice.solve(solutions, allowFreeTypeVariables)) {
if (!currentChoice.isGenericOperatorOrUnavailable() &&
currentChoice.isSymmetricOperator()) {
if (!bestNonGenericScore || score < bestNonGenericScore)
bestNonGenericScore = score;
}

lastSolvedChoice = currentChoice;

Expand Down Expand Up @@ -2578,10 +2584,12 @@ bool ConstraintSystem::solveSimplified(
return tooComplex || !lastSolvedChoice;
}

bool DisjunctionChoice::solve(SmallVectorImpl<Solution> &solutions,
FreeTypeVariableBinding allowFreeTypeVariables) {
Optional<Score>
DisjunctionChoice::solve(SmallVectorImpl<Solution> &solutions,
FreeTypeVariableBinding allowFreeTypeVariables) {
CS->simplifyDisjunctionChoice(Choice);
return !CS->solveRec(solutions, allowFreeTypeVariables);
bool failed = CS->solveRec(solutions, allowFreeTypeVariables);
return failed ? None : Optional<Score>(CS->CurrentScore);
}

bool DisjunctionChoice::isGenericOperatorOrUnavailable() const {
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -2671,8 +2671,8 @@ class DisjunctionChoice {
bool isSymmetricOperator() const;

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

private:
static ValueDecl *getOperatorDecl(Constraint *constraint) {
Expand Down
11 changes: 11 additions & 0 deletions validation-test/Sema/rdar32204609.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: %target-build-swift %s -o %t/a.out
// RUN: %target-run %t/a.out

// REQUIRES: executable_test

let x: Int! = nil
let y: Int! = 1

print(x == y)

0 comments on commit 1bc7a1e

Please sign in to comment.