Skip to content

Commit 02665c5

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 fdb9f22 commit 02665c5

File tree

6 files changed

+83
-78
lines changed

6 files changed

+83
-78
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
@@ -317,11 +317,80 @@ Stmt *BraceStmt::getSingleActiveStatement() const {
317317
return getSingleActiveElement().dyn_cast<Stmt *>();
318318
}
319319

320+
/// Walks the given brace statement and calls the given function reference on
321+
/// every occurrence of an explicit `return` statement.
322+
///
323+
/// \param callback A function reference that takes a `return` statement and
324+
/// returns a boolean value indicating whether to abort the walk.
325+
///
326+
/// \returns `true` if the walk was aborted, `false` otherwise.
327+
static bool walkExplicitReturnStmts(const BraceStmt *BS,
328+
function_ref<bool(ReturnStmt *)> callback) {
329+
class Walker : public ASTWalker {
330+
function_ref<bool(ReturnStmt *)> callback;
331+
332+
public:
333+
Walker(decltype(Walker::callback) callback) : callback(callback) {}
334+
335+
MacroWalking getMacroWalkingBehavior() const override {
336+
return MacroWalking::Arguments;
337+
}
338+
339+
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
340+
return Action::SkipNode(E);
341+
}
342+
343+
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
344+
if (S->isImplicit()) {
345+
return Action::SkipNode(S);
346+
}
347+
348+
auto *returnStmt = dyn_cast<ReturnStmt>(S);
349+
if (!returnStmt) {
350+
return Action::Continue(S);
351+
}
352+
353+
if (callback(returnStmt)) {
354+
return Action::Stop();
355+
}
356+
357+
// Skip children & post walk and continue.
358+
return Action::SkipNode(S);
359+
}
360+
361+
/// Ignore patterns.
362+
PreWalkResult<Pattern *> walkToPatternPre(Pattern *pat) override {
363+
return Action::SkipNode(pat);
364+
}
365+
};
366+
367+
Walker walker(callback);
368+
369+
return const_cast<BraceStmt *>(BS)->walk(walker) == nullptr;
370+
}
371+
372+
bool BraceHasExplicitReturnStmtRequest::evaluate(Evaluator &evaluator,
373+
const BraceStmt *BS) const {
374+
return walkExplicitReturnStmts(BS, [](ReturnStmt *) { return true; });
375+
}
376+
320377
bool BraceStmt::hasExplicitReturnStmt(ASTContext &ctx) const {
321378
return evaluateOrDefault(ctx.evaluator,
322379
BraceHasExplicitReturnStmtRequest{this}, false);
323380
}
324381

382+
void BraceStmt::getExplicitReturnStmts(
383+
ASTContext &ctx, SmallVectorImpl<ReturnStmt *> &results) const {
384+
if (!hasExplicitReturnStmt(ctx)) {
385+
return;
386+
}
387+
388+
walkExplicitReturnStmts(this, [&results](ReturnStmt *RS) {
389+
results.push_back(RS);
390+
return false;
391+
});
392+
}
393+
325394
IsSingleValueStmtResult Stmt::mayProduceSingleValue(ASTContext &ctx) const {
326395
return evaluateOrDefault(ctx.evaluator, IsSingleValueStmtRequest{this, &ctx},
327396
IsSingleValueStmtResult::circularReference());

lib/Sema/BuilderTransform.cpp

Lines changed: 3 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,9 @@ std::optional<BraceStmt *>
918918
TypeChecker::applyResultBuilderBodyTransform(FuncDecl *func, Type builderType) {
919919
// First look for any return statements, and bail if we have any.
920920
auto &ctx = func->getASTContext();
921-
if (auto returnStmts = findReturnStatements(func); !returnStmts.empty()) {
921+
if (SmallVector<ReturnStmt *> returnStmts;
922+
func->getBody()->getExplicitReturnStmts(ctx, returnStmts),
923+
!returnStmts.empty()) {
922924
// One or more explicit 'return' statements were encountered, which
923925
// disables the result builder transform. Warn when we do this.
924926
ctx.Diags.diagnose(
@@ -1222,79 +1224,6 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
12221224
return getTypeMatchSuccess();
12231225
}
12241226

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

lib/Sema/CSDiagnostics.cpp

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

8863-
auto returnStmts = TypeChecker::findReturnStatements(closure);
8863+
SmallVector<ReturnStmt *> returnStmts;
8864+
closure->getBody()->getExplicitReturnStmts(getASTContext(), returnStmts);
88648865
assert(!returnStmts.empty());
88658866

88668867
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: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,8 +468,7 @@ void typeCheckASTNode(ASTNode &node, DeclContext *DC,
468468
std::optional<BraceStmt *> applyResultBuilderBodyTransform(FuncDecl *func,
469469
Type builderType);
470470

471-
/// Find the return statements within the body of the given function.
472-
std::vector<ReturnStmt *> findReturnStatements(AnyFunctionRef fn);
471+
bool typeCheckClosureBody(ClosureExpr *closure);
473472

474473
bool typeCheckTapBody(TapExpr *expr, DeclContext *DC);
475474

0 commit comments

Comments
 (0)