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