Skip to content

Commit 8519334

Browse files
Merge pull request #76749 from AnthonyLatsis/amanita-muscaria
2 parents f9b3f60 + 41adfec commit 8519334

14 files changed

+990
-248
lines changed

include/swift/AST/AnyFunctionRef.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,18 @@ class AnyFunctionRef {
153153
llvm_unreachable("autoclosures don't have statement bodies");
154154
}
155155

156+
/// Returns a boolean value indicating whether the body, if any, contains
157+
/// an explicit `return` statement.
158+
///
159+
/// \returns `true` if the body contains an explicit `return` statement,
160+
/// `false` otherwise.
161+
bool bodyHasExplicitReturnStmt() const;
162+
163+
/// Finds occurrences of explicit `return` statements within the body, if any.
164+
///
165+
/// \param results An out container to which the results are added.
166+
void getExplicitReturnStmts(SmallVectorImpl<ReturnStmt *> &results) const;
167+
156168
DeclContext *getAsDeclContext() const {
157169
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>())
158170
return AFD;

include/swift/AST/Decl.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ namespace swift {
109109
class ProtocolType;
110110
struct RawComment;
111111
enum class ResilienceExpansion : unsigned;
112+
class ReturnStmt;
112113
enum class EffectKind : uint8_t;
113114
enum class PolymorphicEffectKind : uint8_t;
114115
class TrailingWhereClause;
@@ -7675,6 +7676,18 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
76757676
/// parsed.
76767677
bool hasBody() const;
76777678

7679+
/// Returns a boolean value indicating whether the body, if any, contains
7680+
/// an explicit `return` statement.
7681+
///
7682+
/// \returns `true` if the body contains an explicit `return` statement,
7683+
/// `false` otherwise.
7684+
bool bodyHasExplicitReturnStmt() const;
7685+
7686+
/// Finds occurrences of explicit `return` statements within the body, if any.
7687+
///
7688+
/// \param results An out container to which the results are added.
7689+
void getExplicitReturnStmts(SmallVectorImpl<ReturnStmt *> &results) const;
7690+
76787691
/// Returns true if the text of this function's body can be retrieved either
76797692
/// by extracting the text from the source buffer or reading the inlinable
76807693
/// body from a deserialized swiftmodule.

include/swift/AST/Expr.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ namespace swift {
7171
class KeyPathExpr;
7272
class CaptureListExpr;
7373
class ThenStmt;
74+
class ReturnStmt;
7475

7576
enum class ExprKind : uint8_t {
7677
#define EXPR(Id, Parent) Id,
@@ -4051,6 +4052,18 @@ class AbstractClosureExpr : public DeclContext, public Expr {
40514052
/// returns nullptr if the closure doesn't have a body
40524053
BraceStmt *getBody() const;
40534054

4055+
/// Returns a boolean value indicating whether the body, if any, contains
4056+
/// an explicit `return` statement.
4057+
///
4058+
/// \returns `true` if the body contains an explicit `return` statement,
4059+
/// `false` otherwise.
4060+
bool bodyHasExplicitReturnStmt() const;
4061+
4062+
/// Finds occurrences of explicit `return` statements within the body, if any.
4063+
///
4064+
/// \param results An out container to which the results are added.
4065+
void getExplicitReturnStmts(SmallVectorImpl<ReturnStmt *> &results) const;
4066+
40544067
ActorIsolation getActorIsolation() const {
40554068
return actorIsolation;
40564069
}

include/swift/AST/TypeCheckRequests.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3050,9 +3050,9 @@ class AssociatedConformanceRequest
30503050
void cacheResult(ProtocolConformanceRef value) const;
30513051
};
30523052

3053-
class BraceHasReturnRequest
3054-
: public SimpleRequest<BraceHasReturnRequest, bool(const BraceStmt *),
3055-
RequestFlags::Cached> {
3053+
class BraceHasExplicitReturnStmtRequest
3054+
: public SimpleRequest<BraceHasExplicitReturnStmtRequest,
3055+
bool(const BraceStmt *), RequestFlags::Cached> {
30563056
public:
30573057
using SimpleRequest::SimpleRequest;
30583058

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ SWIFT_REQUEST(TypeChecker, HasUserDefinedDesignatedInitRequest,
383383
bool(NominalTypeDecl *), Cached, NoLocationInfo)
384384
SWIFT_REQUEST(TypeChecker, HasMemberwiseInitRequest,
385385
bool(StructDecl *), Cached, NoLocationInfo)
386-
SWIFT_REQUEST(TypeChecker, BraceHasReturnRequest,
386+
SWIFT_REQUEST(TypeChecker, BraceHasExplicitReturnStmtRequest,
387387
bool(const BraceStmt *),
388388
Cached, NoLocationInfo)
389389
SWIFT_REQUEST(TypeChecker, ResolveImplicitMemberRequest,

lib/AST/Decl.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9356,6 +9356,17 @@ bool AbstractFunctionDecl::hasBody() const {
93569356
}
93579357
}
93589358

9359+
bool AbstractFunctionDecl::bodyHasExplicitReturnStmt() const {
9360+
return AnyFunctionRef(const_cast<AbstractFunctionDecl *>(this))
9361+
.bodyHasExplicitReturnStmt();
9362+
}
9363+
9364+
void AbstractFunctionDecl::getExplicitReturnStmts(
9365+
SmallVectorImpl<ReturnStmt *> &results) const {
9366+
AnyFunctionRef(const_cast<AbstractFunctionDecl *>(this))
9367+
.getExplicitReturnStmts(results);
9368+
}
9369+
93599370
/// Expand all preamble macros attached to the given function declaration.
93609371
static std::vector<ASTNode> expandPreamble(AbstractFunctionDecl *func) {
93619372
std::vector<ASTNode> preamble;

lib/AST/Expr.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,6 +1962,17 @@ BraceStmt * AbstractClosureExpr::getBody() const {
19621962
llvm_unreachable("Unknown closure expression");
19631963
}
19641964

1965+
bool AbstractClosureExpr::bodyHasExplicitReturnStmt() const {
1966+
return AnyFunctionRef(const_cast<AbstractClosureExpr *>(this))
1967+
.bodyHasExplicitReturnStmt();
1968+
}
1969+
1970+
void AbstractClosureExpr::getExplicitReturnStmts(
1971+
SmallVectorImpl<ReturnStmt *> &results) const {
1972+
AnyFunctionRef(const_cast<AbstractClosureExpr *>(this))
1973+
.getExplicitReturnStmts(results);
1974+
}
1975+
19651976
Type AbstractClosureExpr::getResultType(
19661977
llvm::function_ref<Type(Expr *)> getType) const {
19671978
auto *E = const_cast<AbstractClosureExpr *>(this);

lib/Sema/BuilderTransform.cpp

Lines changed: 74 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -918,13 +918,13 @@ 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 (evaluateOrDefault(ctx.evaluator, BraceHasReturnRequest{func->getBody()},
922-
false)) {
921+
922+
SmallVector<ReturnStmt *> returnStmts;
923+
func->getExplicitReturnStmts(returnStmts);
924+
925+
if (!returnStmts.empty()) {
923926
// One or more explicit 'return' statements were encountered, which
924927
// disables the result builder transform. Warn when we do this.
925-
auto returnStmts = findReturnStatements(func);
926-
assert(!returnStmts.empty());
927-
928928
ctx.Diags.diagnose(
929929
returnStmts.front()->getReturnLoc(),
930930
diag::result_builder_disabled_by_return_warn, builderType);
@@ -1126,8 +1126,7 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
11261126
// not apply the result builder transform if it contained an explicit return.
11271127
// To maintain source compatibility, we still need to check for HasReturnStmt.
11281128
// https://github.com/apple/swift/issues/64332.
1129-
if (evaluateOrDefault(getASTContext().evaluator,
1130-
BraceHasReturnRequest{fn.getBody()}, false)) {
1129+
if (fn.bodyHasExplicitReturnStmt()) {
11311130
// Diagnostic mode means that solver couldn't reach any viable
11321131
// solution, so let's diagnose presence of a `return` statement
11331132
// in the closure body.
@@ -1235,49 +1234,84 @@ void ConstraintSystem::removeResultBuilderTransform(AnyFunctionRef fn) {
12351234
ASSERT(erased);
12361235
}
12371236

1238-
namespace {
1239-
class ReturnStmtFinder : public ASTWalker {
1240-
std::vector<ReturnStmt *> ReturnStmts;
1237+
/// Walks the given brace statement and calls the given function reference on
1238+
/// every occurrence of an explicit `return` statement.
1239+
///
1240+
/// \param callback A function reference that takes a `return` statement and
1241+
/// returns a boolean value indicating whether to abort the walk.
1242+
///
1243+
/// \returns `true` if the walk was aborted, `false` otherwise.
1244+
static bool walkExplicitReturnStmts(const BraceStmt *BS,
1245+
function_ref<bool(ReturnStmt *)> callback) {
1246+
class Walker : public ASTWalker {
1247+
function_ref<bool(ReturnStmt *)> callback;
1248+
1249+
public:
1250+
Walker(decltype(Walker::callback) callback) : callback(callback) {}
1251+
1252+
MacroWalking getMacroWalkingBehavior() const override {
1253+
return MacroWalking::Arguments;
1254+
}
12411255

1242-
public:
1243-
static std::vector<ReturnStmt *> find(const BraceStmt *BS) {
1244-
ReturnStmtFinder finder;
1245-
const_cast<BraceStmt *>(BS)->walk(finder);
1246-
return std::move(finder.ReturnStmts);
1247-
}
1256+
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
1257+
return Action::SkipNode(E);
1258+
}
12481259

1249-
MacroWalking getMacroWalkingBehavior() const override {
1250-
return MacroWalking::Arguments;
1251-
}
1260+
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
1261+
if (S->isImplicit()) {
1262+
return Action::SkipNode(S);
1263+
}
12521264

1253-
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
1254-
return Action::SkipNode(E);
1255-
}
1265+
auto *returnStmt = dyn_cast<ReturnStmt>(S);
1266+
if (!returnStmt) {
1267+
return Action::Continue(S);
1268+
}
12561269

1257-
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
1258-
// If we see a return statement, note it..
1259-
auto *returnStmt = dyn_cast<ReturnStmt>(S);
1260-
if (!returnStmt || returnStmt->isImplicit())
1261-
return Action::Continue(S);
1270+
if (callback(returnStmt)) {
1271+
return Action::Stop();
1272+
}
12621273

1263-
ReturnStmts.push_back(returnStmt);
1264-
return Action::SkipNode(S);
1265-
}
1274+
// Skip children & post walk and continue.
1275+
return Action::SkipNode(S);
1276+
}
12661277

1267-
/// Ignore patterns.
1268-
PreWalkResult<Pattern *> walkToPatternPre(Pattern *pat) override {
1269-
return Action::SkipNode(pat);
1278+
/// Ignore patterns.
1279+
PreWalkResult<Pattern *> walkToPatternPre(Pattern *pat) override {
1280+
return Action::SkipNode(pat);
1281+
}
1282+
};
1283+
1284+
Walker walker(callback);
1285+
1286+
return const_cast<BraceStmt *>(BS)->walk(walker) == nullptr;
1287+
}
1288+
1289+
bool BraceHasExplicitReturnStmtRequest::evaluate(Evaluator &evaluator,
1290+
const BraceStmt *BS) const {
1291+
return walkExplicitReturnStmts(BS, [](ReturnStmt *) { return true; });
1292+
}
1293+
1294+
bool AnyFunctionRef::bodyHasExplicitReturnStmt() const {
1295+
auto *body = getBody();
1296+
if (!body) {
1297+
return false;
12701298
}
1271-
};
1272-
} // end anonymous namespace
12731299

1274-
bool BraceHasReturnRequest::evaluate(Evaluator &evaluator,
1275-
const BraceStmt *BS) const {
1276-
return !ReturnStmtFinder::find(BS).empty();
1300+
auto &ctx = getAsDeclContext()->getASTContext();
1301+
return evaluateOrDefault(ctx.evaluator,
1302+
BraceHasExplicitReturnStmtRequest{body}, false);
12771303
}
12781304

1279-
std::vector<ReturnStmt *> TypeChecker::findReturnStatements(AnyFunctionRef fn) {
1280-
return ReturnStmtFinder::find(fn.getBody());
1305+
void AnyFunctionRef::getExplicitReturnStmts(
1306+
SmallVectorImpl<ReturnStmt *> &results) const {
1307+
if (!bodyHasExplicitReturnStmt()) {
1308+
return;
1309+
}
1310+
1311+
walkExplicitReturnStmts(getBody(), [&results](ReturnStmt *RS) {
1312+
results.push_back(RS);
1313+
return false;
1314+
});
12811315
}
12821316

12831317
ResultBuilderOpSupport TypeChecker::checkBuilderOpSupport(

lib/Sema/CSDiagnostics.cpp

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

8865-
auto returnStmts = TypeChecker::findReturnStatements(closure);
8865+
SmallVector<ReturnStmt *> returnStmts;
8866+
closure->getExplicitReturnStmts(returnStmts);
88668867
assert(!returnStmts.empty());
88678868

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

0 commit comments

Comments
 (0)