Skip to content

Commit e0702d9

Browse files
committed
[Constraint solver] Generalize solve() for arbitrary solution targets.
Start cleaning up the main “solve” entry point for solving an expression and applying the solution, so it handles arbitrary solution targets. This is another small step that doesn’t do much on its own, but will help with unifying the various places in the code base where we run the solver.
1 parent 40ca1ef commit e0702d9

File tree

4 files changed

+93
-77
lines changed

4 files changed

+93
-77
lines changed

lib/Sema/CSApply.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7331,7 +7331,8 @@ Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
73317331
// If we're supposed to convert the expression to some particular type,
73327332
// do so now.
73337333
if (shouldCoerceToContextualType()) {
7334-
resultExpr = rewriter.coerceToType(resultExpr, convertType,
7334+
resultExpr = rewriter.coerceToType(resultExpr,
7335+
simplifyType(convertType),
73357336
getConstraintLocator(expr));
73367337
} else if (getType(resultExpr)->hasLValueType() &&
73377338
!target.isDiscardedExpr()) {

lib/Sema/CSSolver.cpp

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,22 +1074,22 @@ void ConstraintSystem::shrink(Expr *expr) {
10741074
}
10751075
}
10761076

1077-
static bool debugConstraintSolverForExpr(ASTContext &C, Expr *expr) {
1077+
static bool debugConstraintSolverForTarget(
1078+
ASTContext &C, SolutionApplicationTarget target) {
10781079
if (C.TypeCheckerOpts.DebugConstraintSolver)
10791080
return true;
10801081

10811082
if (C.TypeCheckerOpts.DebugConstraintSolverOnLines.empty())
10821083
// No need to compute the line number to find out it's not present.
10831084
return false;
10841085

1085-
// Get the lines on which the expression starts and ends.
1086+
// Get the lines on which the target starts and ends.
10861087
unsigned startLine = 0, endLine = 0;
1087-
if (expr->getSourceRange().isValid()) {
1088-
auto range =
1089-
Lexer::getCharSourceRangeFromSourceRange(C.SourceMgr,
1090-
expr->getSourceRange());
1091-
startLine = C.SourceMgr.getLineNumber(range.getStart());
1092-
endLine = C.SourceMgr.getLineNumber(range.getEnd());
1088+
SourceRange range = target.getSourceRange();
1089+
if (range.isValid()) {
1090+
auto charRange = Lexer::getCharSourceRangeFromSourceRange(C.SourceMgr, range);
1091+
startLine = C.SourceMgr.getLineNumber(charRange.getStart());
1092+
endLine = C.SourceMgr.getLineNumber(charRange.getEnd());
10931093
}
10941094

10951095
assert(startLine <= endLine && "expr ends before it starts?");
@@ -1107,25 +1107,26 @@ static bool debugConstraintSolverForExpr(ASTContext &C, Expr *expr) {
11071107
return startBound != endBound;
11081108
}
11091109

1110-
bool ConstraintSystem::solve(Expr *&expr,
1111-
Type convertType,
1112-
ExprTypeCheckListener *listener,
1113-
SmallVectorImpl<Solution> &solutions,
1114-
FreeTypeVariableBinding allowFreeTypeVariables) {
1110+
Optional<std::vector<Solution>> ConstraintSystem::solve(
1111+
SolutionApplicationTarget &target,
1112+
ExprTypeCheckListener *listener,
1113+
FreeTypeVariableBinding allowFreeTypeVariables
1114+
) {
11151115
llvm::SaveAndRestore<bool> debugForExpr(
11161116
getASTContext().TypeCheckerOpts.DebugConstraintSolver,
1117-
debugConstraintSolverForExpr(getASTContext(), expr));
1117+
debugConstraintSolverForTarget(getASTContext(), target));
11181118

11191119
/// Dump solutions for debugging purposes.
1120-
auto dumpSolutions = [&] {
1120+
auto dumpSolutions = [&](const SolutionResult &result) {
11211121
// Debug-print the set of solutions.
11221122
if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) {
11231123
auto &log = getASTContext().TypeCheckerDebug->getStream();
1124-
if (solutions.size() == 1) {
1124+
if (result.getKind() == SolutionResult::Success) {
11251125
log << "---Solution---\n";
1126-
solutions[0].dump(log);
1127-
} else {
1128-
for (unsigned i = 0, e = solutions.size(); i != e; ++i) {
1126+
result.getSolution().dump(log);
1127+
} else if (result.getKind() == SolutionResult::Ambiguous) {
1128+
auto solutions = result.getAmbiguousSolutions();
1129+
for (unsigned i : indices(solutions)) {
11291130
log << "--- Solution #" << i << " ---\n";
11301131
solutions[i].dump(log);
11311132
}
@@ -1135,61 +1136,61 @@ bool ConstraintSystem::solve(Expr *&expr,
11351136

11361137
// Take up to two attempts at solving the system. The first attempts to
11371138
// solve a system that is expected to be well-formed, the second kicks in
1138-
// when there is an error and attempts to salvage an ill-formed expression.
1139-
SolutionApplicationTarget target(expr, convertType, /*isDiscarded=*/false);
1139+
// when there is an error and attempts to salvage an ill-formed program.
11401140
for (unsigned stage = 0; stage != 2; ++stage) {
11411141
auto solution = (stage == 0)
11421142
? solveImpl(target, listener, allowFreeTypeVariables)
11431143
: salvage();
11441144

11451145
switch (solution.getKind()) {
1146-
case SolutionResult::Success:
1146+
case SolutionResult::Success: {
11471147
// Return the successful solution.
1148-
solutions.clear();
1149-
solutions.push_back(std::move(solution).takeSolution());
1150-
dumpSolutions();
1151-
return false;
1148+
dumpSolutions(solution);
1149+
std::vector<Solution> result;
1150+
result.push_back(std::move(solution).takeSolution());
1151+
return std::move(result);
1152+
}
11521153

11531154
case SolutionResult::Error:
1154-
return true;
1155+
return None;
11551156

11561157
case SolutionResult::TooComplex:
1157-
getASTContext().Diags.diagnose(expr->getLoc(), diag::expression_too_complex)
1158-
.highlight(expr->getSourceRange());
1158+
getASTContext().Diags.diagnose(
1159+
target.getLoc(), diag::expression_too_complex)
1160+
.highlight(target.getSourceRange());
11591161
solution.markAsDiagnosed();
1160-
return true;
1162+
return None;
11611163

11621164
case SolutionResult::Ambiguous:
11631165
// If salvaging produced an ambiguous result, it has already been
11641166
// diagnosed.
11651167
if (stage == 1) {
11661168
solution.markAsDiagnosed();
1167-
return true;
1169+
return None;
11681170
}
11691171

11701172
if (Options.contains(
11711173
ConstraintSystemFlags::AllowUnresolvedTypeVariables)) {
1174+
dumpSolutions(solution);
11721175
auto ambiguousSolutions = std::move(solution).takeAmbiguousSolutions();
1173-
solutions.assign(std::make_move_iterator(ambiguousSolutions.begin()),
1174-
std::make_move_iterator(ambiguousSolutions.end()));
1175-
dumpSolutions();
1176-
return false;
1176+
std::vector<Solution> result(
1177+
std::make_move_iterator(ambiguousSolutions.begin()),
1178+
std::make_move_iterator(ambiguousSolutions.end()));
1179+
return std::move(result);
11771180
}
11781181

11791182
LLVM_FALLTHROUGH;
11801183

11811184
case SolutionResult::UndiagnosedError:
11821185
if (shouldSuppressDiagnostics()) {
11831186
solution.markAsDiagnosed();
1184-
return true;
1187+
return None;
11851188
}
11861189

11871190
if (stage == 1) {
1188-
diagnoseFailureFor(
1189-
SolutionApplicationTarget(expr, convertType,
1190-
/*isDiscarded=*/false));
1191+
diagnoseFailureFor(target);
11911192
solution.markAsDiagnosed();
1192-
return true;
1193+
return None;
11931194
}
11941195

11951196
// Loop again to try to salvage.

lib/Sema/ConstraintSystem.h

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,6 +1194,11 @@ class SolutionApplicationTarget {
11941194
return expression.convertType;
11951195
}
11961196

1197+
void setExprConversionType(Type type) {
1198+
assert(kind == Kind::expression);
1199+
expression.convertType = type;
1200+
}
1201+
11971202
bool isDiscardedExpr() const {
11981203
assert(kind == Kind::expression);
11991204
return expression.isDiscarded;
@@ -1234,6 +1239,18 @@ class SolutionApplicationTarget {
12341239
return function.body->getSourceRange();
12351240
}
12361241
}
1242+
1243+
/// Retrieve the source location for the target.
1244+
SourceLoc getLoc() const {
1245+
switch (kind) {
1246+
case Kind::expression:
1247+
return expression.expression->getLoc();
1248+
1249+
case Kind::function:
1250+
return function.function.getLoc();
1251+
}
1252+
}
1253+
12371254
/// Walk the contents of the application target.
12381255
SolutionApplicationTarget walk(ASTWalker &walker);
12391256
};
@@ -4104,26 +4121,21 @@ class ConstraintSystem {
41044121
static bool preCheckExpression(Expr *&expr, DeclContext *dc,
41054122
ConstraintSystem *baseCS = nullptr);
41064123

4107-
/// Solve the system of constraints generated from provided expression.
4108-
///
4109-
/// The expression should have already been pre-checked with
4110-
/// preCheckExpression().
4124+
/// Solve the system of constraints generated from provided target.
41114125
///
4112-
/// \param expr The expression to generate constraints from.
4113-
/// \param convertType The expected type of the expression.
4126+
/// \param target The target that we'll generate constraints from, which
4127+
/// may be updated by the solving process.
41144128
/// \param listener The callback to check solving progress.
4115-
/// \param solutions The set of solutions to the system of constraints.
41164129
/// \param allowFreeTypeVariables How to bind free type variables in
41174130
/// the solution.
41184131
///
4119-
/// \returns true is an error occurred, false is system is consistent
4120-
/// and solutions were found.
4121-
bool solve(Expr *&expr,
4122-
Type convertType,
4123-
ExprTypeCheckListener *listener,
4124-
SmallVectorImpl<Solution> &solutions,
4125-
FreeTypeVariableBinding allowFreeTypeVariables
4126-
= FreeTypeVariableBinding::Disallow);
4132+
/// \returns the set of solutions, if any were found, or \c None if an
4133+
/// error occurred. When \c None, an error has been emitted.
4134+
Optional<std::vector<Solution>> solve(
4135+
SolutionApplicationTarget &target,
4136+
ExprTypeCheckListener *listener,
4137+
FreeTypeVariableBinding allowFreeTypeVariables
4138+
= FreeTypeVariableBinding::Disallow);
41274139

41284140
/// Solve the system of constraints.
41294141
///

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2138,34 +2138,36 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
21382138
convertTo = getOptionalType(expr->getLoc(), var);
21392139
}
21402140

2141-
SmallVector<Solution, 4> viable;
21422141
// Attempt to solve the constraint system.
2143-
if (cs.solve(expr, convertTo, listener, viable, allowFreeTypeVariables))
2142+
SolutionApplicationTarget target(
2143+
expr, convertTo,
2144+
options.contains(TypeCheckExprFlags::IsDiscarded));
2145+
auto viable = cs.solve(target, listener, allowFreeTypeVariables);
2146+
if (!viable)
21442147
return Type();
21452148

21462149
// If the client allows the solution to have unresolved type expressions,
21472150
// check for them now. We cannot apply the solution with unresolved TypeVars,
21482151
// because they will leak out into arbitrary places in the resultant AST.
21492152
if (options.contains(TypeCheckExprFlags::AllowUnresolvedTypeVariables) &&
2150-
(viable.size() != 1 ||
2153+
(viable->size() != 1 ||
21512154
(convertType.getType() && convertType.getType()->hasUnresolvedType()))) {
21522155
return ErrorType::get(Context);
21532156
}
21542157

2155-
auto result = expr;
2156-
auto &solution = viable[0];
2158+
auto result = target.getAsExpr();
2159+
auto &solution = (*viable)[0];
21572160
if (!result)
21582161
return Type();
21592162

21602163
// Apply this solution to the constraint system.
21612164
cs.applySolution(solution);
21622165

21632166
// Apply the solution to the expression.
2164-
SolutionApplicationTarget target(
2165-
result, convertType.getType(),
2166-
options.contains(TypeCheckExprFlags::IsDiscarded));
21672167
bool performingDiagnostics =
21682168
options.contains(TypeCheckExprFlags::SubExpressionDiagnostics);
2169+
// FIXME: HACK!
2170+
target.setExprConversionType(convertType.getType());
21692171
auto resultTarget = cs.applySolution(solution, target, performingDiagnostics);
21702172
if (!resultTarget) {
21712173
// Failure already diagnosed, above, as part of applying the solution.
@@ -2244,7 +2246,6 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc,
22442246
ConstraintSystem cs(dc, ConstraintSystemFlags::SuppressDiagnostics);
22452247

22462248
// Attempt to solve the constraint system.
2247-
SmallVector<Solution, 4> viable;
22482249
const Type originalType = expr->getType();
22492250
const bool needClearType = originalType && originalType->hasError();
22502251
const auto recoverOriginalType = [&] () {
@@ -2256,14 +2257,16 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc,
22562257
// re-check.
22572258
if (needClearType)
22582259
expr->setType(Type());
2259-
if (cs.solve(expr, /*convertType*/Type(), listener, viable,
2260-
allowFreeTypeVariables)) {
2260+
SolutionApplicationTarget target(expr, Type(), /*isDiscarded=*/false);
2261+
auto viable = cs.solve(target, listener, allowFreeTypeVariables);
2262+
if (!viable) {
22612263
recoverOriginalType();
22622264
return Type();
22632265
}
22642266

22652267
// Get the expression's simplified type.
2266-
auto &solution = viable[0];
2268+
expr = target.getAsExpr();
2269+
auto &solution = (*viable)[0];
22672270
auto &solutionCS = solution.getConstraintSystem();
22682271
Type exprType = solution.simplifyType(solutionCS.getType(expr));
22692272

@@ -2330,19 +2333,18 @@ void TypeChecker::getPossibleTypesOfExpressionWithoutApplying(
23302333
ConstraintSystem cs(dc, options);
23312334

23322335
// Attempt to solve the constraint system.
2333-
SmallVector<Solution, 4> viable;
2334-
23352336
const Type originalType = expr->getType();
23362337
if (originalType && originalType->hasError())
23372338
expr->setType(Type());
23382339

2339-
cs.solve(expr, /*convertType*/ Type(), listener, viable,
2340-
allowFreeTypeVariables);
2341-
2342-
for (auto &solution : viable) {
2343-
auto exprType = solution.simplifyType(cs.getType(expr));
2344-
assert(exprType && !exprType->hasTypeVariable());
2345-
types.insert(exprType.getPointer());
2340+
SolutionApplicationTarget target(expr, Type(), /*isDiscarded=*/false);
2341+
if (auto viable = cs.solve(target, listener, allowFreeTypeVariables)) {
2342+
expr = target.getAsExpr();
2343+
for (auto &solution : *viable) {
2344+
auto exprType = solution.simplifyType(cs.getType(expr));
2345+
assert(exprType && !exprType->hasTypeVariable());
2346+
types.insert(exprType.getPointer());
2347+
}
23462348
}
23472349
}
23482350

0 commit comments

Comments
 (0)