Skip to content

Commit 10ddb04

Browse files
committed
[ConstraintSystem] Add SuppressDiagnostics/AllowUnresolvedTypeVariables flags
Instead of mixing flags between type-checker and constraint solver, let's move the ones which are useful in constraint system there. Doing so allows for `solveForExpression` to be moved from `TypeChecker` to `ConstraintSystem` which consolidates solver logic. It also allows to set these flags as part of constraint generation/solving, which is sometimes important.
1 parent c3867c8 commit 10ddb04

File tree

5 files changed

+122
-101
lines changed

5 files changed

+122
-101
lines changed

lib/Sema/CSApply.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8088,11 +8088,13 @@ bool ConstraintSystem::applySolutionFix(Expr *expr,
80888088
Expr *ConstraintSystem::applySolution(Solution &solution, Expr *expr,
80898089
Type convertType,
80908090
bool discardedExpr,
8091-
bool suppressDiagnostics,
80928091
bool skipClosures) {
80938092
// If any fixes needed to be applied to arrive at this solution, resolve
80948093
// them to specific expressions.
80958094
if (!solution.Fixes.empty()) {
8095+
if (shouldSuppressDiagnostics())
8096+
return nullptr;
8097+
80968098
// If we can diagnose the problem with the fixits that we've pre-assumed,
80978099
// do so now.
80988100
if (applySolutionFixes(expr, solution))
@@ -8108,7 +8110,7 @@ Expr *ConstraintSystem::applySolution(Solution &solution, Expr *expr,
81088110
for (auto &e : solution.Conformances)
81098111
TC.markConformanceUsed(e.second, DC);
81108112

8111-
ExprRewriter rewriter(*this, solution, suppressDiagnostics);
8113+
ExprRewriter rewriter(*this, solution, shouldSuppressDiagnostics());
81128114
ExprWalker walker(rewriter);
81138115

81148116
// Apply the solution to the expression.

lib/Sema/CSSolver.cpp

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,12 +1319,63 @@ void ConstraintSystem::shrink(Expr *expr) {
13191319
}
13201320
}
13211321

1322+
bool ConstraintSystem::solve(Expr *&expr,
1323+
Type convertType,
1324+
ExprTypeCheckListener *listener,
1325+
SmallVectorImpl<Solution> &solutions,
1326+
FreeTypeVariableBinding allowFreeTypeVariables) {
1327+
// Attempt to solve the constraint system.
1328+
auto solution = solveImpl(expr,
1329+
convertType,
1330+
listener,
1331+
solutions,
1332+
allowFreeTypeVariables);
1333+
1334+
// The constraint system has failed
1335+
if (solution == SolutionKind::Error)
1336+
return true;
1337+
1338+
// If the system is unsolved or there are multiple solutions present but
1339+
// type checker options do not allow unresolved types, let's try to salvage
1340+
if (solution == SolutionKind::Unsolved ||
1341+
(solutions.size() != 1 &&
1342+
!Options.contains(
1343+
ConstraintSystemFlags::AllowUnresolvedTypeVariables))) {
1344+
if (shouldSuppressDiagnostics())
1345+
return true;
1346+
1347+
// Try to provide a decent diagnostic.
1348+
if (salvage(solutions, expr)) {
1349+
// If salvage produced an error message, then it failed to salvage the
1350+
// expression, just bail out having reported the error.
1351+
return true;
1352+
}
1353+
1354+
// The system was salvaged; continue on as if nothing happened.
1355+
}
1356+
1357+
if (TC.getLangOpts().DebugConstraintSolver) {
1358+
auto &log = getASTContext().TypeCheckerDebug->getStream();
1359+
if (solutions.size() == 1) {
1360+
log << "---Solution---\n";
1361+
solutions[0].dump(log);
1362+
} else {
1363+
for (unsigned i = 0, e = solutions.size(); i != e; ++i) {
1364+
log << "--- Solution #" << i << " ---\n";
1365+
solutions[i].dump(log);
1366+
}
1367+
}
1368+
}
1369+
1370+
return false;
1371+
}
1372+
13221373
ConstraintSystem::SolutionKind
1323-
ConstraintSystem::solve(Expr *&expr,
1324-
Type convertType,
1325-
ExprTypeCheckListener *listener,
1326-
SmallVectorImpl<Solution> &solutions,
1327-
FreeTypeVariableBinding allowFreeTypeVariables) {
1374+
ConstraintSystem::solveImpl(Expr *&expr,
1375+
Type convertType,
1376+
ExprTypeCheckListener *listener,
1377+
SmallVectorImpl<Solution> &solutions,
1378+
FreeTypeVariableBinding allowFreeTypeVariables) {
13281379
if (TC.getLangOpts().DebugConstraintSolver) {
13291380
auto &log = getASTContext().TypeCheckerDebug->getStream();
13301381
log << "---Constraint solving for the expression at ";

lib/Sema/ConstraintSystem.h

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,16 @@ enum class ConstraintSystemFlags {
790790
/// If set, this is going to prevent constraint system from erasing all
791791
/// discovered solutions except the best one.
792792
ReturnAllDiscoveredSolutions = 0x04,
793+
794+
/// Set if the client wants diagnostics suppressed.
795+
SuppressDiagnostics = 0x08,
796+
797+
/// If set, the client wants a best-effort solution to the constraint system,
798+
/// but can tolerate a solution where all of the constraints are solved, but
799+
/// not all type variables have been determined. In this case, the constraint
800+
/// system is not applied to the expression AST, but the ConstraintSystem is
801+
/// left in-tact.
802+
AllowUnresolvedTypeVariables = 0x10,
793803
};
794804

795805
/// Options that affect the constraint system as a whole.
@@ -1709,6 +1719,10 @@ class ConstraintSystem {
17091719
return !solverState || solverState->recordFixes;
17101720
}
17111721

1722+
bool shouldSuppressDiagnostics() {
1723+
return Options.contains(ConstraintSystemFlags::SuppressDiagnostics);
1724+
}
1725+
17121726
/// \brief Log and record the application of the fix. Return true iff any
17131727
/// subsequent solution would be worse than the best known solution.
17141728
bool recordFix(Fix fix, ConstraintLocatorBuilder locator);
@@ -2962,7 +2976,6 @@ class ConstraintSystem {
29622976
bool *foundConsistent);
29632977
bool areBindPairConsistent(Constraint *first, Constraint *second);
29642978

2965-
public:
29662979
/// \brief Solve the system of constraints generated from provided expression.
29672980
///
29682981
/// \param expr The expression to generate constraints from.
@@ -2974,12 +2987,34 @@ class ConstraintSystem {
29742987
///
29752988
/// \returns Error is an error occurred, Solved is system is consistent
29762989
/// and solutions were found, Unsolved otherwise.
2977-
SolutionKind solve(Expr *&expr,
2978-
Type convertType,
2979-
ExprTypeCheckListener *listener,
2980-
SmallVectorImpl<Solution> &solutions,
2981-
FreeTypeVariableBinding allowFreeTypeVariables
2982-
= FreeTypeVariableBinding::Disallow);
2990+
SolutionKind solveImpl(Expr *&expr,
2991+
Type convertType,
2992+
ExprTypeCheckListener *listener,
2993+
SmallVectorImpl<Solution> &solutions,
2994+
FreeTypeVariableBinding allowFreeTypeVariables
2995+
= FreeTypeVariableBinding::Disallow);
2996+
2997+
public:
2998+
/// \brief Solve the system of constraints generated from provided expression.
2999+
///
3000+
/// The expression should have already been pre-checked with
3001+
/// preCheckExpression().
3002+
///
3003+
/// \param expr The expression to generate constraints from.
3004+
/// \param convertType The expected type of the expression.
3005+
/// \param listener The callback to check solving progress.
3006+
/// \param solutions The set of solutions to the system of constraints.
3007+
/// \param allowFreeTypeVariables How to bind free type variables in
3008+
/// the solution.
3009+
///
3010+
/// \returns true is an error occurred, false is system is consistent
3011+
/// and solutions were found.
3012+
bool solve(Expr *&expr,
3013+
Type convertType,
3014+
ExprTypeCheckListener *listener,
3015+
SmallVectorImpl<Solution> &solutions,
3016+
FreeTypeVariableBinding allowFreeTypeVariables
3017+
= FreeTypeVariableBinding::Disallow);
29833018

29843019
/// \brief Solve the system of constraints.
29853020
///
@@ -3067,7 +3102,6 @@ class ConstraintSystem {
30673102
/// non-single expression closures.
30683103
Expr *applySolution(Solution &solution, Expr *expr,
30693104
Type convertType, bool discardedExpr,
3070-
bool suppressDiagnostics,
30713105
bool skipClosures);
30723106

30733107
/// \brief Apply a given solution to the expression to the top-level

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 20 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1909,57 +1909,6 @@ bool GenericRequirementsCheckListener::diagnoseUnsatisfiedRequirement(
19091909
return false;
19101910
}
19111911

1912-
bool TypeChecker::
1913-
solveForExpression(Expr *&expr, DeclContext *dc, Type convertType,
1914-
FreeTypeVariableBinding allowFreeTypeVariables,
1915-
ExprTypeCheckListener *listener, ConstraintSystem &cs,
1916-
SmallVectorImpl<Solution> &viable,
1917-
TypeCheckExprOptions options) {
1918-
// Attempt to solve the constraint system.
1919-
auto solution = cs.solve(expr,
1920-
convertType,
1921-
listener,
1922-
viable,
1923-
allowFreeTypeVariables);
1924-
1925-
// The constraint system has failed
1926-
if (solution == ConstraintSystem::SolutionKind::Error)
1927-
return true;
1928-
1929-
// If the system is unsolved or there are multiple solutions present but
1930-
// type checker options do not allow unresolved types, let's try to salvage
1931-
if (solution == ConstraintSystem::SolutionKind::Unsolved
1932-
|| (viable.size() != 1 &&
1933-
!options.contains(TypeCheckExprFlags::AllowUnresolvedTypeVariables))) {
1934-
if (options.contains(TypeCheckExprFlags::SuppressDiagnostics))
1935-
return true;
1936-
1937-
// Try to provide a decent diagnostic.
1938-
if (cs.salvage(viable, expr)) {
1939-
// If salvage produced an error message, then it failed to salvage the
1940-
// expression, just bail out having reported the error.
1941-
return true;
1942-
}
1943-
1944-
// The system was salvaged; continue on as if nothing happened.
1945-
}
1946-
1947-
if (getLangOpts().DebugConstraintSolver) {
1948-
auto &log = Context.TypeCheckerDebug->getStream();
1949-
if (viable.size() == 1) {
1950-
log << "---Solution---\n";
1951-
viable[0].dump(log);
1952-
} else {
1953-
for (unsigned i = 0, e = viable.size(); i != e; ++i) {
1954-
log << "--- Solution #" << i << " ---\n";
1955-
viable[i].dump(log);
1956-
}
1957-
}
1958-
}
1959-
1960-
return false;
1961-
}
1962-
19631912
#pragma mark High-level entry points
19641913
Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
19651914
TypeLoc convertType,
@@ -1976,6 +1925,13 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
19761925

19771926
// Construct a constraint system from this expression.
19781927
ConstraintSystemOptions csOptions = ConstraintSystemFlags::AllowFixes;
1928+
1929+
if (options.contains(TypeCheckExprFlags::SuppressDiagnostics))
1930+
csOptions |= ConstraintSystemFlags::SuppressDiagnostics;
1931+
1932+
if (options.contains(TypeCheckExprFlags::AllowUnresolvedTypeVariables))
1933+
csOptions |= ConstraintSystemFlags::AllowUnresolvedTypeVariables;
1934+
19791935
ConstraintSystem cs(*this, dc, csOptions);
19801936
cs.baseCS = baseCS;
19811937
CleanupIllFormedExpressionRAII cleanup(expr);
@@ -2007,9 +1963,6 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
20071963
// that we don't later treat it as an actual conversion constraint.
20081964
if (options.contains(TypeCheckExprFlags::ConvertTypeIsOnlyAHint))
20091965
convertType = TypeLoc();
2010-
2011-
bool suppressDiagnostics =
2012-
options.contains(TypeCheckExprFlags::SuppressDiagnostics);
20131966

20141967
// If the client can handle unresolved type variables, leave them in the
20151968
// system.
@@ -2019,8 +1972,8 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
20191972

20201973
// Attempt to solve the constraint system.
20211974
SmallVector<Solution, 4> viable;
2022-
if (solveForExpression(expr, dc, convertType.getType(),
2023-
allowFreeTypeVariables, listener, cs, viable, options))
1975+
if (cs.solve(expr, convertType.getType(), listener, viable,
1976+
allowFreeTypeVariables))
20241977
return Type();
20251978

20261979
// If the client allows the solution to have unresolved type expressions,
@@ -2046,11 +1999,10 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
20461999
}
20472000

20482001
// Apply the solution to the expression.
2049-
bool isDiscarded = options.contains(TypeCheckExprFlags::IsDiscarded);
2050-
bool skipClosures = options.contains(TypeCheckExprFlags::SkipMultiStmtClosures);
2051-
result = cs.applySolution(solution, result, convertType.getType(),
2052-
isDiscarded, suppressDiagnostics,
2053-
skipClosures);
2002+
result = cs.applySolution(
2003+
solution, result, convertType.getType(),
2004+
options.contains(TypeCheckExprFlags::IsDiscarded),
2005+
options.contains(TypeCheckExprFlags::SkipMultiStmtClosures));
20542006
if (!result) {
20552007
// Failure already diagnosed, above, as part of applying the solution.
20562008
return Type();
@@ -2072,7 +2024,7 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
20722024

20732025
// Unless the client has disabled them, perform syntactic checks on the
20742026
// expression now.
2075-
if (!suppressDiagnostics &&
2027+
if (!cs.shouldSuppressDiagnostics() &&
20762028
!options.contains(TypeCheckExprFlags::DisableStructuralChecks)) {
20772029
bool isExprStmt = options.contains(TypeCheckExprFlags::IsExprStmt);
20782030
performSyntacticExprDiagnostics(*this, result, dc, isExprStmt);
@@ -2092,7 +2044,7 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc,
20922044
referencedDecl = nullptr;
20932045

20942046
// Construct a constraint system from this expression.
2095-
ConstraintSystem cs(*this, dc, ConstraintSystemFlags::AllowFixes);
2047+
ConstraintSystem cs(*this, dc, ConstraintSystemFlags::SuppressDiagnostics);
20962048
CleanupIllFormedExpressionRAII cleanup(expr);
20972049

20982050
// Attempt to solve the constraint system.
@@ -2108,9 +2060,8 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc,
21082060
// re-check.
21092061
if (needClearType)
21102062
expr->setType(Type());
2111-
if (solveForExpression(expr, dc, /*convertType*/Type(),
2112-
allowFreeTypeVariables, listener, cs, viable,
2113-
TypeCheckExprFlags::SuppressDiagnostics)) {
2063+
if (cs.solve(expr, /*convertType*/Type(), listener, viable,
2064+
allowFreeTypeVariables)) {
21142065
recoverOriginalType();
21152066
return Type();
21162067
}
@@ -2177,8 +2128,8 @@ void TypeChecker::getPossibleTypesOfExpressionWithoutApplying(
21772128

21782129
// Construct a constraint system from this expression.
21792130
ConstraintSystemOptions options;
2180-
options |= ConstraintSystemFlags::AllowFixes;
21812131
options |= ConstraintSystemFlags::ReturnAllDiscoveredSolutions;
2132+
options |= ConstraintSystemFlags::SuppressDiagnostics;
21822133

21832134
ConstraintSystem cs(*this, dc, options);
21842135

@@ -2194,9 +2145,8 @@ void TypeChecker::getPossibleTypesOfExpressionWithoutApplying(
21942145
if (originalType && originalType->hasError())
21952146
expr->setType(Type());
21962147

2197-
solveForExpression(expr, dc, /*convertType*/ Type(), allowFreeTypeVariables,
2198-
listener, cs, viable,
2199-
TypeCheckExprFlags::SuppressDiagnostics);
2148+
cs.solve(expr, /*convertType*/ Type(), listener, viable,
2149+
allowFreeTypeVariables);
22002150
}
22012151

22022152
for (auto &solution : viable) {

lib/Sema/TypeChecker.h

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,22 +1487,6 @@ class TypeChecker final : public LazyResolver {
14871487
/// expression and folding sequence expressions.
14881488
bool preCheckExpression(Expr *&expr, DeclContext *dc);
14891489

1490-
/// Sets up and solves the constraint system \p cs to type check the given
1491-
/// expression.
1492-
///
1493-
/// The expression should have already been pre-checked with
1494-
/// preCheckExpression().
1495-
///
1496-
/// \returns true if an error occurred, false otherwise.
1497-
///
1498-
/// \see typeCheckExpression
1499-
bool solveForExpression(Expr *&expr, DeclContext *dc, Type convertType,
1500-
FreeTypeVariableBinding allowFreeTypeVariables,
1501-
ExprTypeCheckListener *listener,
1502-
constraints::ConstraintSystem &cs,
1503-
SmallVectorImpl<constraints::Solution> &viable,
1504-
TypeCheckExprOptions options);
1505-
15061490
/// \name Name lookup
15071491
///
15081492
/// Routines that perform name lookup.

0 commit comments

Comments
 (0)