[CSSolver] Add skeleton of iterative solve

The idea so to split solving into non-recursive steps,
represented by `SolverStep`, each of the steps is resposible
for a unit of work e.g. attempting type variable or
disjunction bindings/choices.

Each step could produce more work via "follow-up" steps,
complete "partial" solution when it's done, or error which
terminates solver loop.
This commit is contained in:
Pavel Yaskevich
2018-09-03 00:12:32 -07:00
parent 9bff72aa8d
commit daf4c2f3b5
5 changed files with 278 additions and 0 deletions

View File

@@ -13,6 +13,7 @@
// This file implements the constraint solver used in the type checker.
//
//===----------------------------------------------------------------------===//
#include "CSStep.h"
#include "ConstraintGraph.h"
#include "ConstraintSystem.h"
#include "TypeCheckType.h"
@@ -24,6 +25,7 @@
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <list>
#include <memory>
#include <tuple>
@@ -1556,6 +1558,68 @@ bool ConstraintSystem::solveRec(SmallVectorImpl<Solution> &solutions) {
return !anySolutions;
}
bool ConstraintSystem::solveIteratively(
Expr *expr, SmallVectorImpl<Solution> &solutions,
FreeTypeVariableBinding allowFreeTypeVariables) {
SolverState state(expr, *this, allowFreeTypeVariables);
std::list<SolverStep> workList;
// First step is always wraps whole constraint system.
workList.push_back(
SolverStep::create(*this, TypeVariables, InactiveConstraints, solutions));
// Execute steps in LIFO order, which means that
// each individual step would either end up producing
// a solution, or producing another set of mergeable
// steps to take before arriving to solution.
while (!workList.empty()) {
auto &step = workList.back();
// Now let's try to advance to the next step,
// which should produce another steps to follow,
// or error, which means that we'll have to stop.
{
SolutionKind result;
std::list<SolverStep> followupSteps;
std::tie(result, followupSteps) = step.advance();
switch (result) {
// Step has been solved successfully by either
// producing a partial solution, or more steps
// toward that solution.
case SolutionKind::Solved: {
workList.pop_back();
break;
}
// Keep this step in the work list to return to it
// once all other steps are done, this could be a
// disjunction which has to peek a new choice until
// it completely runs out of choices, or type variable
// binding.
case SolutionKind::Unsolved:
break;
// It was impossible to produce a solution for this step,
// let's terminate the solver loop.
case SolutionKind::Error:
return true;
}
workList.splice(workList.end(), followupSteps);
}
}
// Filter deduced solutions, try to figure out if there is
// a single best solution to use, if not explicitly disabled
// by constraint system options.
if (!retainAllSolutions())
filterSolutions(solutions, state.ExprWeights);
// We fail if there is no solution or the expression was too complex.
return solutions.empty() || getExpressionTooComplex(solutions);
}
/// Whether we should short-circuit a disjunction that already has a
/// solution when we encounter the given constraint.
static bool shortCircuitDisjunctionAt(Constraint *constraint,