Skip to content

Commit 66d4cd1

Browse files
committed
[NFC] AST, Sema: Make TypeChecker::findReturnStatements a member of BraceStmt
Also rename it to `getExplicitReturnStmts` for clarity and have it take a `SmallVector` out parameter instead as a small optimization and to discourage use of this new method as an alternative to `BraceStmt::hasExplicitReturnStatement`.
1 parent 6c2cd5d commit 66d4cd1

File tree

6 files changed

+82
-79
lines changed

6 files changed

+82
-79
lines changed

include/swift/AST/Stmt.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class FuncDecl;
4444
class AbstractFunctionDecl;
4545
class Pattern;
4646
class PatternBindingDecl;
47+
class ReturnStmt;
4748
class VarDecl;
4849
class CaseStmt;
4950
class DoCatchStmt;
@@ -244,6 +245,12 @@ class BraceStmt final : public Stmt,
244245
/// statement, `false` otherwise.
245246
bool hasExplicitReturnStmt(ASTContext &ctx) const;
246247

248+
/// Finds occurrences of explicit `return` statements within the brace
249+
/// statement.
250+
/// \param results An out container to which the results are added.
251+
void getExplicitReturnStmts(ASTContext &ctx,
252+
SmallVectorImpl<ReturnStmt *> &results) const;
253+
247254
static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Brace; }
248255
};
249256

lib/AST/Stmt.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,11 +334,80 @@ Stmt *BraceStmt::getSingleActiveStatement() const {
334334
return getSingleActiveElement().dyn_cast<Stmt *>();
335335
}
336336

337+
/// Walks the given brace statement and calls the given function reference on
338+
/// every occurrence of an explicit `return` statement.
339+
///
340+
/// \param callback A function reference that takes a `return` statement and
341+
/// returns a boolean value indicating whether to abort the walk.
342+
///
343+
/// \returns `true` if the walk was aborted, `false` otherwise.
344+
static bool walkExplicitReturnStmts(const BraceStmt *BS,
345+
function_ref<bool(ReturnStmt *)> callback) {
346+
class Walker : public ASTWalker {
347+
function_ref<bool(ReturnStmt *)> callback;
348+
349+
public:
350+
Walker(decltype(Walker::callback) callback) : callback(callback) {}
351+
352+
MacroWalking getMacroWalkingBehavior() const override {
353+
return MacroWalking::Arguments;
354+
}
355+
356+
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
357+
return Action::SkipNode(E);
358+
}
359+
360+
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
361+
if (S->isImplicit()) {
362+
return Action::SkipNode(S);
363+
}
364+
365+
auto *returnStmt = dyn_cast<ReturnStmt>(S);
366+
if (!returnStmt) {
367+
return Action::Continue(S);
368+
}
369+
370+
if (callback(returnStmt)) {
371+
return Action::Stop();
372+
}
373+
374+
// Skip children & post walk and continue.
375+
return Action::SkipNode(S);
376+
}
377+
378+
/// Ignore patterns.
379+
PreWalkResult<Pattern *> walkToPatternPre(Pattern *pat) override {
380+
return Action::SkipNode(pat);
381+
}
382+
};
383+
384+
Walker walker(callback);
385+
386+
return const_cast<BraceStmt *>(BS)->walk(walker) == nullptr;
387+
}
388+
389+
bool BraceHasExplicitReturnStmtRequest::evaluate(Evaluator &evaluator,
390+
const BraceStmt *BS) const {
391+
return walkExplicitReturnStmts(BS, [](ReturnStmt *) { return true; });
392+
}
393+
337394
bool BraceStmt::hasExplicitReturnStmt(ASTContext &ctx) const {
338395
return evaluateOrDefault(ctx.evaluator,
339396
BraceHasExplicitReturnStmtRequest{this}, false);
340397
}
341398

399+
void BraceStmt::getExplicitReturnStmts(
400+
ASTContext &ctx, SmallVectorImpl<ReturnStmt *> &results) const {
401+
if (!hasExplicitReturnStmt(ctx)) {
402+
return;
403+
}
404+
405+
walkExplicitReturnStmts(this, [&results](ReturnStmt *RS) {
406+
results.push_back(RS);
407+
return false;
408+
});
409+
}
410+
342411
IsSingleValueStmtResult Stmt::mayProduceSingleValue(ASTContext &ctx) const {
343412
return evaluateOrDefault(ctx.evaluator, IsSingleValueStmtRequest{this, &ctx},
344413
IsSingleValueStmtResult::circularReference());

lib/Sema/BuilderTransform.cpp

Lines changed: 3 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,9 @@ std::optional<BraceStmt *>
922922
TypeChecker::applyResultBuilderBodyTransform(FuncDecl *func, Type builderType) {
923923
// First look for any return statements, and bail if we have any.
924924
auto &ctx = func->getASTContext();
925-
if (auto returnStmts = findReturnStatements(func); !returnStmts.empty()) {
925+
if (SmallVector<ReturnStmt *> returnStmts;
926+
func->getBody()->getExplicitReturnStmts(ctx, returnStmts),
927+
!returnStmts.empty()) {
926928
// One or more explicit 'return' statements were encountered, which
927929
// disables the result builder transform. Warn when we do this.
928930
ctx.Diags.diagnose(
@@ -1226,79 +1228,6 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
12261228
return getTypeMatchSuccess();
12271229
}
12281230

1229-
/// Walks the given brace statement and calls the given function reference on
1230-
/// every occurrence of an explicit `return` statement.
1231-
///
1232-
/// \param callback A function reference that takes a `return` statement and
1233-
/// returns a boolean value indicating whether to abort the walk.
1234-
///
1235-
/// \returns `true` if the walk was aborted, `false` otherwise.
1236-
static bool walkExplicitReturnStmts(const BraceStmt *BS,
1237-
function_ref<bool(ReturnStmt *)> callback) {
1238-
class Walker : public ASTWalker {
1239-
function_ref<bool(ReturnStmt *)> callback;
1240-
1241-
public:
1242-
Walker(decltype(Walker::callback) callback) : callback(callback) {}
1243-
1244-
MacroWalking getMacroWalkingBehavior() const override {
1245-
return MacroWalking::Arguments;
1246-
}
1247-
1248-
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
1249-
return Action::SkipNode(E);
1250-
}
1251-
1252-
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
1253-
if (S->isImplicit()) {
1254-
return Action::SkipNode(S);
1255-
}
1256-
1257-
auto *returnStmt = dyn_cast<ReturnStmt>(S);
1258-
if (!returnStmt) {
1259-
return Action::Continue(S);
1260-
}
1261-
1262-
if (callback(returnStmt)) {
1263-
return Action::Stop();
1264-
}
1265-
1266-
// Skip children & post walk and continue.
1267-
return Action::SkipNode(S);
1268-
}
1269-
1270-
/// Ignore patterns.
1271-
PreWalkResult<Pattern *> walkToPatternPre(Pattern *pat) override {
1272-
return Action::SkipNode(pat);
1273-
}
1274-
};
1275-
1276-
Walker walker(callback);
1277-
1278-
return const_cast<BraceStmt *>(BS)->walk(walker) == nullptr;
1279-
}
1280-
1281-
bool BraceHasExplicitReturnStmtRequest::evaluate(Evaluator &evaluator,
1282-
const BraceStmt *BS) const {
1283-
return walkExplicitReturnStmts(BS, [](ReturnStmt *) { return true; });
1284-
}
1285-
1286-
std::vector<ReturnStmt *> TypeChecker::findReturnStatements(AnyFunctionRef fn) {
1287-
if (!fn.getBody()->hasExplicitReturnStmt(
1288-
fn.getAsDeclContext()->getASTContext())) {
1289-
return std::vector<ReturnStmt *>();
1290-
}
1291-
1292-
std::vector<ReturnStmt *> results;
1293-
1294-
walkExplicitReturnStmts(fn.getBody(), [&results](ReturnStmt *RS) {
1295-
results.push_back(RS);
1296-
return false;
1297-
});
1298-
1299-
return results;
1300-
}
1301-
13021231
ResultBuilderOpSupport TypeChecker::checkBuilderOpSupport(
13031232
Type builderType, DeclContext *dc, Identifier fnName,
13041233
ArrayRef<Identifier> argLabels, SmallVectorImpl<ValueDecl *> *allResults) {

lib/Sema/CSDiagnostics.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8736,7 +8736,8 @@ bool ReferenceToInvalidDeclaration::diagnoseAsError() {
87368736
bool InvalidReturnInResultBuilderBody::diagnoseAsError() {
87378737
auto *closure = castToExpr<ClosureExpr>(getAnchor());
87388738

8739-
auto returnStmts = TypeChecker::findReturnStatements(closure);
8739+
SmallVector<ReturnStmt *> returnStmts;
8740+
closure->getBody()->getExplicitReturnStmts(getASTContext(), returnStmts);
87408741
assert(!returnStmts.empty());
87418742

87428743
auto loc = returnStmts.front()->getReturnLoc();

lib/Sema/TypeCheckRequestFunctions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ static Type inferResultBuilderType(ValueDecl *decl) {
236236
// Check whether there are any return statements in the function's body.
237237
// If there are, the result builder transform will be disabled,
238238
// so don't infer a result builder.
239-
if (!TypeChecker::findReturnStatements(funcDecl).empty())
239+
if (funcDecl->getBody()->hasExplicitReturnStmt(dc->getASTContext()))
240240
return Type();
241241

242242
// Find all of the potentially inferred result builder types.

lib/Sema/TypeChecker.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -460,9 +460,6 @@ void typeCheckASTNode(ASTNode &node, DeclContext *DC,
460460
std::optional<BraceStmt *> applyResultBuilderBodyTransform(FuncDecl *func,
461461
Type builderType);
462462

463-
/// Find the return statements within the body of the given function.
464-
std::vector<ReturnStmt *> findReturnStatements(AnyFunctionRef fn);
465-
466463
bool typeCheckClosureBody(ClosureExpr *closure);
467464

468465
bool typeCheckTapBody(TapExpr *expr, DeclContext *DC);

0 commit comments

Comments
 (0)