@@ -1074,22 +1074,22 @@ void ConstraintSystem::shrink(Expr *expr) {
1074
1074
}
1075
1075
}
1076
1076
1077
- static bool debugConstraintSolverForExpr (ASTContext &C, Expr *expr) {
1077
+ static bool debugConstraintSolverForTarget (
1078
+ ASTContext &C, SolutionApplicationTarget target) {
1078
1079
if (C.TypeCheckerOpts .DebugConstraintSolver )
1079
1080
return true ;
1080
1081
1081
1082
if (C.TypeCheckerOpts .DebugConstraintSolverOnLines .empty ())
1082
1083
// No need to compute the line number to find out it's not present.
1083
1084
return false ;
1084
1085
1085
- // Get the lines on which the expression starts and ends.
1086
+ // Get the lines on which the target starts and ends.
1086
1087
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 ());
1093
1093
}
1094
1094
1095
1095
assert (startLine <= endLine && " expr ends before it starts?" );
@@ -1107,25 +1107,44 @@ static bool debugConstraintSolverForExpr(ASTContext &C, Expr *expr) {
1107
1107
return startBound != endBound;
1108
1108
}
1109
1109
1110
- bool ConstraintSystem::solve (Expr *&expr,
1111
- Type convertType,
1112
- ExprTypeCheckListener *listener,
1113
- SmallVectorImpl<Solution> &solutions,
1114
- FreeTypeVariableBinding allowFreeTypeVariables) {
1110
+ // / If we aren't certain that we've emitted a diagnostic, emit a fallback
1111
+ // / diagnostic.
1112
+ static void maybeProduceFallbackDiagnostic (
1113
+ ConstraintSystem &cs, SolutionApplicationTarget target) {
1114
+ if (cs.Options .contains (ConstraintSystemFlags::SubExpressionDiagnostics) ||
1115
+ cs.Options .contains (ConstraintSystemFlags::SuppressDiagnostics))
1116
+ return ;
1117
+
1118
+ // Before producing fatal error here, let's check if there are any "error"
1119
+ // diagnostics already emitted or waiting to be emitted. Because they are
1120
+ // a better indication of the problem.
1121
+ ASTContext &ctx = cs.getASTContext ();
1122
+ if (ctx.Diags .hadAnyError () || ctx.hasDelayedConformanceErrors ())
1123
+ return ;
1124
+
1125
+ ctx.Diags .diagnose (target.getLoc (), diag::failed_to_produce_diagnostic);
1126
+ }
1127
+
1128
+ Optional<std::vector<Solution>> ConstraintSystem::solve (
1129
+ SolutionApplicationTarget &target,
1130
+ ExprTypeCheckListener *listener,
1131
+ FreeTypeVariableBinding allowFreeTypeVariables
1132
+ ) {
1115
1133
llvm::SaveAndRestore<bool > debugForExpr (
1116
1134
getASTContext ().TypeCheckerOpts .DebugConstraintSolver ,
1117
- debugConstraintSolverForExpr (getASTContext (), expr ));
1135
+ debugConstraintSolverForTarget (getASTContext (), target ));
1118
1136
1119
1137
// / Dump solutions for debugging purposes.
1120
- auto dumpSolutions = [&] {
1138
+ auto dumpSolutions = [&]( const SolutionResult &result) {
1121
1139
// Debug-print the set of solutions.
1122
1140
if (getASTContext ().TypeCheckerOpts .DebugConstraintSolver ) {
1123
1141
auto &log = getASTContext ().TypeCheckerDebug ->getStream ();
1124
- if (solutions. size () == 1 ) {
1142
+ if (result. getKind () == SolutionResult::Success ) {
1125
1143
log << " ---Solution---\n " ;
1126
- solutions[0 ].dump (log );
1127
- } else {
1128
- for (unsigned i = 0 , e = solutions.size (); i != e; ++i) {
1144
+ result.getSolution ().dump (log );
1145
+ } else if (result.getKind () == SolutionResult::Ambiguous) {
1146
+ auto solutions = result.getAmbiguousSolutions ();
1147
+ for (unsigned i : indices (solutions)) {
1129
1148
log << " --- Solution #" << i << " ---\n " ;
1130
1149
solutions[i].dump (log );
1131
1150
}
@@ -1135,59 +1154,62 @@ bool ConstraintSystem::solve(Expr *&expr,
1135
1154
1136
1155
// Take up to two attempts at solving the system. The first attempts to
1137
1156
// 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 .
1157
+ // when there is an error and attempts to salvage an ill-formed program .
1139
1158
for (unsigned stage = 0 ; stage != 2 ; ++stage) {
1140
1159
auto solution = (stage == 0 )
1141
- ? solveImpl (expr, convertType , listener, allowFreeTypeVariables)
1160
+ ? solveImpl (target , listener, allowFreeTypeVariables)
1142
1161
: salvage ();
1143
1162
1144
1163
switch (solution.getKind ()) {
1145
- case SolutionResult::Success:
1164
+ case SolutionResult::Success: {
1146
1165
// Return the successful solution.
1147
- solutions.clear ();
1148
- solutions.push_back (std::move (solution).takeSolution ());
1149
- dumpSolutions ();
1150
- return false ;
1166
+ dumpSolutions (solution);
1167
+ std::vector<Solution> result;
1168
+ result.push_back (std::move (solution).takeSolution ());
1169
+ return std::move (result);
1170
+ }
1151
1171
1152
1172
case SolutionResult::Error:
1153
- return true ;
1173
+ maybeProduceFallbackDiagnostic (*this , target);
1174
+ return None;
1154
1175
1155
1176
case SolutionResult::TooComplex:
1156
- getASTContext ().Diags .diagnose (expr->getLoc (), diag::expression_too_complex)
1157
- .highlight (expr->getSourceRange ());
1177
+ getASTContext ().Diags .diagnose (
1178
+ target.getLoc (), diag::expression_too_complex)
1179
+ .highlight (target.getSourceRange ());
1158
1180
solution.markAsDiagnosed ();
1159
- return true ;
1181
+ return None ;
1160
1182
1161
1183
case SolutionResult::Ambiguous:
1162
1184
// If salvaging produced an ambiguous result, it has already been
1163
1185
// diagnosed.
1164
1186
if (stage == 1 ) {
1165
1187
solution.markAsDiagnosed ();
1166
- return true ;
1188
+ return None ;
1167
1189
}
1168
1190
1169
1191
if (Options.contains (
1170
1192
ConstraintSystemFlags::AllowUnresolvedTypeVariables)) {
1193
+ dumpSolutions (solution);
1171
1194
auto ambiguousSolutions = std::move (solution).takeAmbiguousSolutions ();
1172
- solutions.assign (std::make_move_iterator (ambiguousSolutions.begin ()),
1173
- std::make_move_iterator (ambiguousSolutions.end ()));
1174
- dumpSolutions ();
1175
- solution.markAsDiagnosed ();
1176
- return false ;
1195
+ std::vector<Solution> result (
1196
+ std::make_move_iterator (ambiguousSolutions.begin ()),
1197
+ std::make_move_iterator (ambiguousSolutions.end ()));
1198
+ return std::move (result);
1177
1199
}
1178
1200
1179
1201
LLVM_FALLTHROUGH;
1180
1202
1181
1203
case SolutionResult::UndiagnosedError:
1182
1204
if (shouldSuppressDiagnostics ()) {
1183
1205
solution.markAsDiagnosed ();
1184
- return true ;
1206
+ return None ;
1185
1207
}
1186
1208
1187
1209
if (stage == 1 ) {
1188
- diagnoseFailureFor (expr );
1210
+ diagnoseFailureFor (target );
1189
1211
solution.markAsDiagnosed ();
1190
- return true ;
1212
+ return None ;
1191
1213
}
1192
1214
1193
1215
// Loop again to try to salvage.
@@ -1200,14 +1222,13 @@ bool ConstraintSystem::solve(Expr *&expr,
1200
1222
}
1201
1223
1202
1224
SolutionResult
1203
- ConstraintSystem::solveImpl (Expr *&expr,
1204
- Type convertType,
1225
+ ConstraintSystem::solveImpl (SolutionApplicationTarget &target,
1205
1226
ExprTypeCheckListener *listener,
1206
1227
FreeTypeVariableBinding allowFreeTypeVariables) {
1207
1228
if (getASTContext ().TypeCheckerOpts .DebugConstraintSolver ) {
1208
1229
auto &log = getASTContext ().TypeCheckerDebug ->getStream ();
1209
- log << " ---Constraint solving for the expression at " ;
1210
- auto R = expr-> getSourceRange ();
1230
+ log << " ---Constraint solving at " ;
1231
+ auto R = target. getSourceRange ();
1211
1232
if (R.isValid ()) {
1212
1233
R.print (log , getASTContext ().SourceMgr , /* PrintText=*/ false );
1213
1234
} else {
@@ -1219,6 +1240,7 @@ ConstraintSystem::solveImpl(Expr *&expr,
1219
1240
assert (!solverState && " cannot be used directly" );
1220
1241
1221
1242
// Set up the expression type checker timer.
1243
+ Expr *expr = target.getAsExpr ();
1222
1244
Timer.emplace (expr, *this );
1223
1245
1224
1246
Expr *origExpr = expr;
@@ -1232,14 +1254,12 @@ ConstraintSystem::solveImpl(Expr *&expr,
1232
1254
if (auto generatedExpr = generateConstraints (expr, DC))
1233
1255
expr = generatedExpr;
1234
1256
else {
1235
- if (listener)
1236
- listener->constraintGenerationFailed (expr);
1237
1257
return SolutionResult::forError ();
1238
1258
}
1239
1259
1240
1260
// If there is a type that we're expected to convert to, add the conversion
1241
1261
// constraint.
1242
- if (convertType) {
1262
+ if (Type convertType = target. getExprConversionType () ) {
1243
1263
// Determine whether we know more about the contextual type.
1244
1264
ContextualTypePurpose ctp = CTP_Unused;
1245
1265
bool isOpaqueReturnType = false ;
@@ -1286,6 +1306,8 @@ ConstraintSystem::solveImpl(Expr *&expr,
1286
1306
if (getExpressionTooComplex (solutions))
1287
1307
return SolutionResult::forTooComplex ();
1288
1308
1309
+ target.setExpr (expr);
1310
+
1289
1311
switch (solutions.size ()) {
1290
1312
case 0 :
1291
1313
return SolutionResult::forUndiagnosedError ();
0 commit comments