Skip to content

Commit f176e30

Browse files
committed
[ConstraintSolver] Use a flag to prevent solver from removing possible solutions
In some situations e.g. while trying to shrink domains of the type variables before attempting search, use a flag to tell constraint system to retain all of the viable solutions otherwise solver could loose some of the information required to produce complete solution. Resolves: rdar://problem/32726044 (cherry picked from commit 6231f85)
1 parent 9cf48a8 commit f176e30

File tree

4 files changed

+62
-21
lines changed

4 files changed

+62
-21
lines changed

lib/Sema/CSRanking.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ void ConstraintSystem::increaseScore(ScoreKind kind, unsigned value) {
9393
}
9494

9595
bool ConstraintSystem::worseThanBestSolution() const {
96+
if (retainAllSolutions())
97+
return false;
98+
9699
if (!solverState || !solverState->BestScore ||
97100
CurrentScore <= *solverState->BestScore)
98101
return false;

lib/Sema/CSSolver.cpp

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ Solution ConstraintSystem::finalize(
110110
Solution solution(*this, CurrentScore);
111111

112112
// Update the best score we've seen so far.
113-
if (solverState) {
113+
if (solverState && !retainAllSolutions()) {
114114
assert(!solverState->BestScore || CurrentScore <= *solverState->BestScore);
115115
solverState->BestScore = CurrentScore;
116116
}
@@ -1499,7 +1499,8 @@ bool ConstraintSystem::Candidate::solve(
14991499
};
15001500

15011501
// Allocate new constraint system for sub-expression.
1502-
ConstraintSystem cs(TC, DC, None);
1502+
ConstraintSystem cs(TC, DC,
1503+
ConstraintSystemFlags::ReturnAllDiscoveredSolutions);
15031504

15041505
// Cleanup after constraint system generation/solving,
15051506
// because it would assign types to expressions, which
@@ -2066,17 +2067,11 @@ bool ConstraintSystem::solve(SmallVectorImpl<Solution> &solutions,
20662067
// Solve the system.
20672068
solveRec(solutions, allowFreeTypeVariables);
20682069

2069-
// If there is more than one viable system, attempt to pick the best
2070-
// solution.
2071-
auto size = solutions.size();
2072-
if (size > 1 &&
2073-
!Options.contains(ConstraintSystemFlags::ReturnAllDiscoveredSolutions)) {
2074-
if (auto best = findBestSolution(solutions, /*minimize=*/false)) {
2075-
if (*best != 0)
2076-
solutions[0] = std::move(solutions[*best]);
2077-
solutions.erase(solutions.begin() + 1, solutions.end());
2078-
}
2079-
}
2070+
// Filter deduced solutions, try to figure out if there is
2071+
// a single best solution to use, if not explicitly disabled
2072+
// by constraint system options.
2073+
if (!retainAllSolutions())
2074+
filterSolutions(solutions);
20802075

20812076
// We fail if there is no solution.
20822077
return solutions.empty();
@@ -2289,11 +2284,8 @@ bool ConstraintSystem::solveRec(SmallVectorImpl<Solution> &solutions,
22892284
auto &solutions = partialSolutions[component];
22902285
// If there's a single best solution, keep only that one.
22912286
// Otherwise, the set of solutions will at least have been minimized.
2292-
if (auto best = findBestSolution(solutions, /*minimize=*/true)) {
2293-
if (*best > 0)
2294-
solutions[0] = std::move(solutions[*best]);
2295-
solutions.erase(solutions.begin() + 1, solutions.end());
2296-
}
2287+
if (!retainAllSolutions())
2288+
filterSolutions(solutions, /*minimize=*/true);
22972289
}
22982290

22992291
// Produce all combinations of partial solutions.

lib/Sema/ConstraintSystem.h

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,6 +1386,13 @@ class ConstraintSystem {
13861386
bool hasFreeTypeVariables();
13871387

13881388
private:
1389+
/// \brief Indicates if the constraint system should retain all of the
1390+
/// solutions it has deduced regardless of their score.
1391+
bool retainAllSolutions() const {
1392+
return Options.contains(
1393+
ConstraintSystemFlags::ReturnAllDiscoveredSolutions);
1394+
}
1395+
13891396
/// \brief Finalize this constraint system; we're done attempting to solve
13901397
/// it.
13911398
///
@@ -1407,8 +1414,28 @@ class ConstraintSystem {
14071414
/// diagnostic for it and returning true. If the fixit hint turned out to be
14081415
/// bogus, this returns false and doesn't emit anything.
14091416
bool applySolutionFix(Expr *expr, const Solution &solution, unsigned fixNo);
1410-
1411-
1417+
1418+
/// \brief If there is more than one viable solution,
1419+
/// attempt to pick the best solution and remove all of the rest.
1420+
///
1421+
/// \param solutions The set of solutions to filter.
1422+
///
1423+
/// \param minimize The flag which idicates if the
1424+
/// set of solutions should be filtered even if there is
1425+
/// no single best solution, see `findBestSolution` for
1426+
/// more details.
1427+
void filterSolutions(SmallVectorImpl<Solution> &solutions,
1428+
bool minimize = false) {
1429+
if (solutions.size() < 2)
1430+
return;
1431+
1432+
if (auto best = findBestSolution(solutions, minimize)) {
1433+
if (*best != 0)
1434+
solutions[0] = std::move(solutions[*best]);
1435+
solutions.erase(solutions.begin() + 1, solutions.end());
1436+
}
1437+
}
1438+
14121439
/// \brief Restore the type variable bindings to what they were before
14131440
/// we attempted to solve this constraint system.
14141441
///

test/Constraints/diagnostics.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -977,4 +977,23 @@ let _: KeyPath<R32101765, Float> = \R32101765.prop32101765
977977
let _: KeyPath<R32101765, Float> = \.prop32101765.unknown
978978
// expected-error@-1 {{type 'Int' has no member 'unknown'}}
979979
let _: KeyPath<R32101765, Float> = \R32101765.prop32101765.unknown
980-
// expected-error@-1 {{type 'Int' has no member 'unknown'}}
980+
// expected-error@-1 {{type 'Int' has no member 'unknown'}}
981+
982+
// rdar://problem/32726044 - shrink reduced domains too far
983+
984+
public protocol P_32726044 {}
985+
986+
extension Int: P_32726044 {}
987+
extension Float: P_32726044 {}
988+
989+
public func *(lhs: P_32726044, rhs: P_32726044) -> Double {
990+
fatalError()
991+
}
992+
993+
func rdar32726044() -> Float {
994+
var f: Float = 0
995+
f = Float(1) * 100 // Ok
996+
let _: Float = Float(42) + 0 // Ok
997+
return f
998+
}
999+

0 commit comments

Comments
 (0)