@@ -920,23 +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 = 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 )) {
940927 // One or more explicit 'return' statements were encountered, which
941928 // disables the result builder transform. Warn when we do this.
942929 auto returnStmts = findReturnStatements (func);
@@ -970,7 +957,10 @@ TypeChecker::applyResultBuilderBodyTransform(FuncDecl *func, Type builderType) {
970957
971958 return std::nullopt ;
972959 }
973- }
960+
961+ auto target = SyntacticElementTarget (func);
962+ if (ConstraintSystem::preCheckTarget (target))
963+ return nullptr ;
974964
975965 ConstraintSystemOptions options = ConstraintSystemFlags::AllowFixes;
976966 auto resultInterfaceTy = func->getResultInterfaceType ();
@@ -1018,8 +1008,7 @@ TypeChecker::applyResultBuilderBodyTransform(FuncDecl *func, Type builderType) {
10181008 cs.Options |= ConstraintSystemFlags::ForCodeCompletion;
10191009 cs.solveForCodeCompletion (solutions);
10201010
1021- SyntacticElementTarget funcTarget (func);
1022- CompletionContextFinder analyzer (funcTarget, func->getDeclContext ());
1011+ CompletionContextFinder analyzer (target, func->getDeclContext ());
10231012 if (analyzer.hasCompletion ()) {
10241013 filterSolutionsForCodeCompletion (solutions, analyzer);
10251014 for (const auto &solution : solutions) {
@@ -1066,7 +1055,7 @@ TypeChecker::applyResultBuilderBodyTransform(FuncDecl *func, Type builderType) {
10661055
10671056 case SolutionResult::Kind::UndiagnosedError:
10681057 reportSolutionsToSolutionCallback (salvagedResult);
1069- cs.diagnoseFailureFor (SyntacticElementTarget (func) );
1058+ cs.diagnoseFailureFor (target );
10701059 salvagedResult.markAsDiagnosed ();
10711060 return nullptr ;
10721061
@@ -1100,8 +1089,7 @@ TypeChecker::applyResultBuilderBodyTransform(FuncDecl *func, Type builderType) {
11001089 cs.applySolution (solutions.front ());
11011090
11021091 // 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)) {
11051093 performSyntacticDiagnosticsForTarget (*result, /* isExprStmt*/ false );
11061094 auto *body = result->getFunctionBody ();
11071095
@@ -1142,21 +1130,8 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
11421130 // not apply the result builder transform if it contained an explicit return.
11431131 // To maintain source compatibility, we still need to check for HasReturnStmt.
11441132 // 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 )) {
11601135 // Diagnostic mode means that solver couldn't reach any viable
11611136 // solution, so let's diagnose presence of a `return` statement
11621137 // in the closure body.
@@ -1257,138 +1232,48 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
12571232}
12581233
12591234namespace {
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 {
12661236 std::vector<ReturnStmt *> ReturnStmts;
1267- bool HasError = false ;
1268-
1269- bool hasReturnStmt () const { return !ReturnStmts.empty (); }
12701237
12711238public:
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 );
12961243 }
12971244
12981245 MacroWalking getMacroWalkingBehavior () const override {
12991246 return MacroWalking::Arguments;
13001247 }
13011248
13021249 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);
13311251 }
13321252
13331253 PreWalkResult<Stmt *> walkToStmtPre (Stmt *S) override {
13341254 // 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);
13551258
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);
13671261 }
13681262
13691263 // / Ignore patterns.
13701264 PreWalkResult<Pattern *> walkToPatternPre (Pattern *pat) override {
13711265 return Action::SkipNode (pat);
13721266 }
13731267};
1268+ } // end anonymous namespace
13741269
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 ();
13851273}
13861274
13871275std::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 ());
13921277}
13931278
13941279ResultBuilderOpSupport TypeChecker::checkBuilderOpSupport (
0 commit comments