@@ -920,25 +920,10 @@ class ResultBuilderTransform
920
920
921
921
std::optional<BraceStmt *>
922
922
TypeChecker::applyResultBuilderBodyTransform (FuncDecl *func, Type builderType) {
923
- // Pre-check the body: pre-check any expressions in it and look
924
- // for return statements.
925
- //
926
- // If we encountered an error or there was an explicit result type,
927
- // bail out and report that to the caller.
923
+ // First look for any return statements, and bail if we have any.
928
924
auto &ctx = func->getASTContext ();
929
- auto request =
930
- PreCheckResultBuilderRequest{{AnyFunctionRef (func),
931
- /* SuppressDiagnostics=*/ false }};
932
- switch (evaluateOrDefault (ctx.evaluator , request,
933
- ResultBuilderBodyPreCheck::Error)) {
934
- case ResultBuilderBodyPreCheck::Okay:
935
- // If the pre-check was okay, apply the result-builder transform.
936
- break ;
937
-
938
- case ResultBuilderBodyPreCheck::Error:
939
- return nullptr ;
940
-
941
- case ResultBuilderBodyPreCheck::HasReturnStmt: {
925
+ if (evaluateOrDefault (ctx.evaluator , BraceHasReturnRequest{func->getBody ()},
926
+ false )) {
942
927
// One or more explicit 'return' statements were encountered, which
943
928
// disables the result builder transform. Warn when we do this.
944
929
auto returnStmts = findReturnStatements (func);
@@ -972,7 +957,10 @@ TypeChecker::applyResultBuilderBodyTransform(FuncDecl *func, Type builderType) {
972
957
973
958
return std::nullopt;
974
959
}
975
- }
960
+
961
+ auto target = SyntacticElementTarget (func);
962
+ if (ConstraintSystem::preCheckTarget (target))
963
+ return nullptr ;
976
964
977
965
ConstraintSystemOptions options = ConstraintSystemFlags::AllowFixes;
978
966
auto resultInterfaceTy = func->getResultInterfaceType ();
@@ -1020,8 +1008,7 @@ TypeChecker::applyResultBuilderBodyTransform(FuncDecl *func, Type builderType) {
1020
1008
cs.Options |= ConstraintSystemFlags::ForCodeCompletion;
1021
1009
cs.solveForCodeCompletion (solutions);
1022
1010
1023
- SyntacticElementTarget funcTarget (func);
1024
- CompletionContextFinder analyzer (funcTarget, func->getDeclContext ());
1011
+ CompletionContextFinder analyzer (target, func->getDeclContext ());
1025
1012
if (analyzer.hasCompletion ()) {
1026
1013
filterSolutionsForCodeCompletion (solutions, analyzer);
1027
1014
for (const auto &solution : solutions) {
@@ -1068,7 +1055,7 @@ TypeChecker::applyResultBuilderBodyTransform(FuncDecl *func, Type builderType) {
1068
1055
1069
1056
case SolutionResult::Kind::UndiagnosedError:
1070
1057
reportSolutionsToSolutionCallback (salvagedResult);
1071
- cs.diagnoseFailureFor (SyntacticElementTarget (func) );
1058
+ cs.diagnoseFailureFor (target );
1072
1059
salvagedResult.markAsDiagnosed ();
1073
1060
return nullptr ;
1074
1061
@@ -1102,8 +1089,7 @@ TypeChecker::applyResultBuilderBodyTransform(FuncDecl *func, Type builderType) {
1102
1089
cs.applySolution (solutions.front ());
1103
1090
1104
1091
// Apply the solution to the function body.
1105
- if (auto result =
1106
- cs.applySolution (solutions.front (), SyntacticElementTarget (func))) {
1092
+ if (auto result = cs.applySolution (solutions.front (), target)) {
1107
1093
performSyntacticDiagnosticsForTarget (*result, /* isExprStmt*/ false );
1108
1094
auto *body = result->getFunctionBody ();
1109
1095
@@ -1144,22 +1130,8 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
1144
1130
// not apply the result builder transform if it contained an explicit return.
1145
1131
// To maintain source compatibility, we still need to check for HasReturnStmt.
1146
1132
// https://github.com/apple/swift/issues/64332.
1147
- auto request =
1148
- PreCheckResultBuilderRequest{{fn, /* SuppressDiagnostics=*/ false }};
1149
- switch (evaluateOrDefault (getASTContext ().evaluator , request,
1150
- ResultBuilderBodyPreCheck::Error)) {
1151
- case ResultBuilderBodyPreCheck::Okay:
1152
- // If the pre-check was okay, apply the result-builder transform.
1153
- break ;
1154
-
1155
- case ResultBuilderBodyPreCheck::Error: {
1156
- llvm_unreachable (
1157
- " Running PreCheckResultBuilderRequest on a function shouldn't run "
1158
- " preCheckExpression and thus we should never enter this case." );
1159
- break ;
1160
- }
1161
-
1162
- case ResultBuilderBodyPreCheck::HasReturnStmt:
1133
+ if (evaluateOrDefault (getASTContext ().evaluator ,
1134
+ BraceHasReturnRequest{fn.getBody ()}, false )) {
1163
1135
// Diagnostic mode means that solver couldn't reach any viable
1164
1136
// solution, so let's diagnose presence of a `return` statement
1165
1137
// in the closure body.
@@ -1260,139 +1232,48 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
1260
1232
}
1261
1233
1262
1234
namespace {
1263
-
1264
- // / Pre-check all the expressions in the body.
1265
- class PreCheckResultBuilderApplication : public ASTWalker {
1266
- AnyFunctionRef Fn;
1267
- bool SkipPrecheck = false ;
1268
- bool SuppressDiagnostics = false ;
1235
+ class ReturnStmtFinder : public ASTWalker {
1269
1236
std::vector<ReturnStmt *> ReturnStmts;
1270
- bool HasError = false ;
1271
-
1272
- bool hasReturnStmt () const { return !ReturnStmts.empty (); }
1273
1237
1274
1238
public:
1275
- PreCheckResultBuilderApplication (AnyFunctionRef fn, bool skipPrecheck,
1276
- bool suppressDiagnostics)
1277
- : Fn(fn), SkipPrecheck(skipPrecheck),
1278
- SuppressDiagnostics (suppressDiagnostics) {}
1279
-
1280
- const std::vector<ReturnStmt *> getReturnStmts () const { return ReturnStmts; }
1281
-
1282
- ResultBuilderBodyPreCheck run () {
1283
- Stmt *oldBody = Fn.getBody ();
1284
-
1285
- Stmt *newBody = oldBody->walk (*this );
1286
-
1287
- // If the walk was aborted, it was because we had a problem of some kind.
1288
- assert ((newBody == nullptr ) == HasError &&
1289
- " unexpected short-circuit while walking body" );
1290
- if (HasError)
1291
- return ResultBuilderBodyPreCheck::Error;
1292
-
1293
- assert (oldBody == newBody && " pre-check walk wasn't in-place?" );
1294
-
1295
- if (hasReturnStmt ())
1296
- return ResultBuilderBodyPreCheck::HasReturnStmt;
1297
-
1298
- return ResultBuilderBodyPreCheck::Okay;
1239
+ static std::vector<ReturnStmt *> find (const BraceStmt *BS) {
1240
+ ReturnStmtFinder finder;
1241
+ const_cast <BraceStmt *>(BS)->walk (finder);
1242
+ return std::move (finder.ReturnStmts );
1299
1243
}
1300
1244
1301
1245
MacroWalking getMacroWalkingBehavior () const override {
1302
1246
return MacroWalking::Arguments;
1303
1247
}
1304
1248
1305
1249
PreWalkResult<Expr *> walkToExprPre (Expr *E) override {
1306
- if (SkipPrecheck)
1307
- return Action::SkipNode (E);
1308
-
1309
- // Pre-check the expression. If this fails, abort the walk immediately.
1310
- // Otherwise, replace the expression with the result of pre-checking.
1311
- // In either case, don't recurse into the expression.
1312
- {
1313
- auto *DC = Fn.getAsDeclContext ();
1314
- auto &diagEngine = DC->getASTContext ().Diags ;
1315
-
1316
- // Suppress any diagnostics which could be produced by this expression.
1317
- DiagnosticTransaction transaction (diagEngine);
1318
-
1319
- HasError |= ConstraintSystem::preCheckExpression (E, DC);
1320
-
1321
- HasError |= transaction.hasErrors ();
1322
-
1323
- if (!HasError)
1324
- HasError |= containsErrorExpr (E);
1325
-
1326
- if (SuppressDiagnostics)
1327
- transaction.abort ();
1328
-
1329
- if (HasError)
1330
- return Action::Stop ();
1331
-
1332
- return Action::SkipNode (E);
1333
- }
1250
+ return Action::SkipNode (E);
1334
1251
}
1335
1252
1336
1253
PreWalkResult<Stmt *> walkToStmtPre (Stmt *S) override {
1337
1254
// If we see a return statement, note it..
1338
- if (auto returnStmt = dyn_cast<ReturnStmt>(S)) {
1339
- if (!returnStmt->isImplicit ()) {
1340
- ReturnStmts.push_back (returnStmt);
1341
- return Action::SkipNode (S);
1342
- }
1343
- }
1344
-
1345
- // Otherwise, recurse into the statement normally.
1346
- return Action::Continue (S);
1347
- }
1348
-
1349
- // / Check whether given expression (including single-statement
1350
- // / closures) contains `ErrorExpr` as one of its sub-expressions.
1351
- bool containsErrorExpr (Expr *expr) {
1352
- bool hasError = false ;
1353
-
1354
- expr->forEachChildExpr ([&](Expr *expr) -> Expr * {
1355
- hasError |= isa<ErrorExpr>(expr);
1356
- if (hasError)
1357
- return nullptr ;
1255
+ auto *returnStmt = dyn_cast<ReturnStmt>(S);
1256
+ if (!returnStmt || returnStmt->isImplicit ())
1257
+ return Action::Continue (S);
1358
1258
1359
- if (auto *closure = dyn_cast<ClosureExpr>(expr)) {
1360
- if (closure->hasSingleExpressionBody ()) {
1361
- hasError |= containsErrorExpr (closure->getSingleExpressionBody ());
1362
- return hasError ? nullptr : expr;
1363
- }
1364
- }
1365
-
1366
- return expr;
1367
- });
1368
-
1369
- return hasError;
1259
+ ReturnStmts.push_back (returnStmt);
1260
+ return Action::SkipNode (S);
1370
1261
}
1371
1262
1372
1263
// / Ignore patterns.
1373
1264
PreWalkResult<Pattern *> walkToPatternPre (Pattern *pat) override {
1374
1265
return Action::SkipNode (pat);
1375
1266
}
1376
1267
};
1268
+ } // end anonymous namespace
1377
1269
1378
- }
1379
-
1380
- ResultBuilderBodyPreCheck PreCheckResultBuilderRequest::evaluate (
1381
- Evaluator &evaluator, PreCheckResultBuilderDescriptor owner) const {
1382
- // Closures should already be pre-checked when we run this, so there's no need
1383
- // to pre-check them again.
1384
- bool skipPrecheck = owner.Fn .getAbstractClosureExpr ();
1385
- return PreCheckResultBuilderApplication (
1386
- owner.Fn , skipPrecheck,
1387
- /* suppressDiagnostics=*/ owner.SuppressDiagnostics )
1388
- .run ();
1270
+ bool BraceHasReturnRequest::evaluate (Evaluator &evaluator,
1271
+ const BraceStmt *BS) const {
1272
+ return !ReturnStmtFinder::find (BS).empty ();
1389
1273
}
1390
1274
1391
1275
std::vector<ReturnStmt *> TypeChecker::findReturnStatements (AnyFunctionRef fn) {
1392
- PreCheckResultBuilderApplication precheck (fn, /* skipPreCheck=*/ true ,
1393
- /* SuppressDiagnostics=*/ true );
1394
- (void )precheck.run ();
1395
- return precheck.getReturnStmts ();
1276
+ return ReturnStmtFinder::find (fn.getBody ());
1396
1277
}
1397
1278
1398
1279
ResultBuilderOpSupport TypeChecker::checkBuilderOpSupport (
0 commit comments