@@ -920,25 +920,10 @@ class ResultBuilderTransform
920920
921921std::optional<BraceStmt *>
922922TypeChecker::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.
928924 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 )) {
942927 // One or more explicit 'return' statements were encountered, which
943928 // disables the result builder transform. Warn when we do this.
944929 auto returnStmts = findReturnStatements (func);
@@ -972,7 +957,10 @@ TypeChecker::applyResultBuilderBodyTransform(FuncDecl *func, Type builderType) {
972957
973958 return std::nullopt ;
974959 }
975- }
960+
961+ auto target = SyntacticElementTarget (func);
962+ if (ConstraintSystem::preCheckTarget (target))
963+ return nullptr ;
976964
977965 ConstraintSystemOptions options = ConstraintSystemFlags::AllowFixes;
978966 auto resultInterfaceTy = func->getResultInterfaceType ();
@@ -1020,8 +1008,7 @@ TypeChecker::applyResultBuilderBodyTransform(FuncDecl *func, Type builderType) {
10201008 cs.Options |= ConstraintSystemFlags::ForCodeCompletion;
10211009 cs.solveForCodeCompletion (solutions);
10221010
1023- SyntacticElementTarget funcTarget (func);
1024- CompletionContextFinder analyzer (funcTarget, func->getDeclContext ());
1011+ CompletionContextFinder analyzer (target, func->getDeclContext ());
10251012 if (analyzer.hasCompletion ()) {
10261013 filterSolutionsForCodeCompletion (solutions, analyzer);
10271014 for (const auto &solution : solutions) {
@@ -1068,7 +1055,7 @@ TypeChecker::applyResultBuilderBodyTransform(FuncDecl *func, Type builderType) {
10681055
10691056 case SolutionResult::Kind::UndiagnosedError:
10701057 reportSolutionsToSolutionCallback (salvagedResult);
1071- cs.diagnoseFailureFor (SyntacticElementTarget (func) );
1058+ cs.diagnoseFailureFor (target );
10721059 salvagedResult.markAsDiagnosed ();
10731060 return nullptr ;
10741061
@@ -1102,8 +1089,7 @@ TypeChecker::applyResultBuilderBodyTransform(FuncDecl *func, Type builderType) {
11021089 cs.applySolution (solutions.front ());
11031090
11041091 // 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)) {
11071093 performSyntacticDiagnosticsForTarget (*result, /* isExprStmt*/ false );
11081094 auto *body = result->getFunctionBody ();
11091095
@@ -1144,22 +1130,8 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
11441130 // not apply the result builder transform if it contained an explicit return.
11451131 // To maintain source compatibility, we still need to check for HasReturnStmt.
11461132 // 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 )) {
11631135 // Diagnostic mode means that solver couldn't reach any viable
11641136 // solution, so let's diagnose presence of a `return` statement
11651137 // in the closure body.
@@ -1260,139 +1232,48 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
12601232}
12611233
12621234namespace {
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 {
12691236 std::vector<ReturnStmt *> ReturnStmts;
1270- bool HasError = false ;
1271-
1272- bool hasReturnStmt () const { return !ReturnStmts.empty (); }
12731237
12741238public:
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 );
12991243 }
13001244
13011245 MacroWalking getMacroWalkingBehavior () const override {
13021246 return MacroWalking::Arguments;
13031247 }
13041248
13051249 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);
13341251 }
13351252
13361253 PreWalkResult<Stmt *> walkToStmtPre (Stmt *S) override {
13371254 // 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);
13581258
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);
13701261 }
13711262
13721263 // / Ignore patterns.
13731264 PreWalkResult<Pattern *> walkToPatternPre (Pattern *pat) override {
13741265 return Action::SkipNode (pat);
13751266 }
13761267};
1268+ } // end anonymous namespace
13771269
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 ();
13891273}
13901274
13911275std::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 ());
13961277}
13971278
13981279ResultBuilderOpSupport TypeChecker::checkBuilderOpSupport (
0 commit comments