Skip to content

Commit 9b64990

Browse files
committed
[AST] Remove the "single expression body" bit
Remove this bit from function decls and closures. Instead, for closures, infer it from the presence of a single return or single expression AST node in the body, which ought to be equivalent, and automatically takes result builders into consideration. We can also completely drop this query from AbstractFunctionDecl, replacing it instead with a bit on ReturnStmt.
1 parent 9cf8f5b commit 9b64990

25 files changed

+160
-161
lines changed

include/swift/AST/AnyFunctionRef.h

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,6 @@ class AnyFunctionRef {
9494
return !TheFunction.get<AbstractClosureExpr *>()->getType().isNull();
9595
}
9696

97-
bool hasSingleExpressionBody() const {
98-
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>())
99-
return AFD->hasSingleExpressionBody();
100-
return TheFunction.get<AbstractClosureExpr *>()->hasSingleExpressionBody();
101-
}
102-
10397
ParameterList *getParameters() const {
10498
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>())
10599
return AFD->getParameters();
@@ -146,33 +140,31 @@ class AnyFunctionRef {
146140
return cast<AutoClosureExpr>(ACE)->getBody();
147141
}
148142

149-
void setParsedBody(BraceStmt *stmt, bool isSingleExpression) {
143+
void setParsedBody(BraceStmt *stmt) {
150144
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) {
151145
AFD->setBody(stmt, AbstractFunctionDecl::BodyKind::Parsed);
152-
AFD->setHasSingleExpressionBody(isSingleExpression);
153146
return;
154147
}
155148

156149
auto *ACE = TheFunction.get<AbstractClosureExpr *>();
157150
if (auto *CE = dyn_cast<ClosureExpr>(ACE)) {
158-
CE->setBody(stmt, isSingleExpression);
151+
CE->setBody(stmt);
159152
CE->setBodyState(ClosureExpr::BodyState::ReadyForTypeChecking);
160153
return;
161154
}
162155

163156
llvm_unreachable("autoclosures don't have statement bodies");
164157
}
165158

166-
void setTypecheckedBody(BraceStmt *stmt, bool isSingleExpression) {
159+
void setTypecheckedBody(BraceStmt *stmt) {
167160
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) {
168161
AFD->setBody(stmt, AbstractFunctionDecl::BodyKind::TypeChecked);
169-
AFD->setHasSingleExpressionBody(isSingleExpression);
170162
return;
171163
}
172164

173165
auto *ACE = TheFunction.get<AbstractClosureExpr *>();
174166
if (auto *CE = dyn_cast<ClosureExpr>(ACE)) {
175-
CE->setBody(stmt, isSingleExpression);
167+
CE->setBody(stmt);
176168
CE->setBodyState(ClosureExpr::BodyState::TypeCheckedWithSignature);
177169
return;
178170
}

include/swift/AST/Decl.h

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
464464
SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2,
465465
StaticSpelling : 2
466466
);
467-
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+2+2+2+8+1+1+1+1+1+1+1,
467+
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+2+2+2+8+1+1+1+1+1+1,
468468
/// \see AbstractFunctionDecl::BodyKind
469469
BodyKind : 3,
470470

@@ -492,9 +492,6 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
492492
/// Whether the function body throws.
493493
Throws : 1,
494494

495-
/// Whether this member's body consists of a single expression.
496-
HasSingleExpressionBody : 1,
497-
498495
/// Whether peeking into this function detected nested type declarations.
499496
/// This is set when skipping over the decl at parsing.
500497
HasNestedTypeDeclarations : 1,
@@ -7177,7 +7174,6 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
71777174
Bits.AbstractFunctionDecl.Overridden = false;
71787175
Bits.AbstractFunctionDecl.Async = Async;
71797176
Bits.AbstractFunctionDecl.Throws = Throws;
7180-
Bits.AbstractFunctionDecl.HasSingleExpressionBody = false;
71817177
Bits.AbstractFunctionDecl.HasNestedTypeDeclarations = false;
71827178
Bits.AbstractFunctionDecl.DistributedThunk = false;
71837179
}
@@ -7211,14 +7207,6 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
72117207
}
72127208

72137209
public:
7214-
void setHasSingleExpressionBody(bool Has = true) {
7215-
Bits.AbstractFunctionDecl.HasSingleExpressionBody = Has;
7216-
}
7217-
7218-
bool hasSingleExpressionBody() const {
7219-
return Bits.AbstractFunctionDecl.HasSingleExpressionBody;
7220-
}
7221-
72227210
/// Returns the string for the base name, or "_" if this is unnamed.
72237211
StringRef getNameStr() const {
72247212
assert(!getName().isSpecial() && "Cannot get string for special names");

include/swift/AST/Expr.h

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3927,9 +3927,7 @@ class AbstractClosureExpr : public DeclContext, public Expr {
39273927
bool hasSingleExpressionBody() const;
39283928

39293929
/// Retrieve the body for closure that has a single expression for
3930-
/// its body.
3931-
///
3932-
/// Only valid when \c hasSingleExpressionBody() is true.
3930+
/// its body, or \c nullptr if there is no single expression body.
39333931
Expr *getSingleExpressionBody() const;
39343932

39353933
/// Returns the body of closures that have a body
@@ -4055,9 +4053,9 @@ class ClosureExpr : public AbstractClosureExpr {
40554053
/// The explicitly-specified result type.
40564054
llvm::PointerIntPair<TypeExpr *, 2, BodyState> ExplicitResultTypeAndBodyState;
40574055

4058-
/// The body of the closure, along with a bit indicating whether it
4059-
/// was originally just a single expression.
4060-
llvm::PointerIntPair<BraceStmt *, 1, bool> Body;
4056+
/// The body of the closure.
4057+
BraceStmt *Body;
4058+
40614059
public:
40624060
ClosureExpr(const DeclAttributes &attributes,
40634061
SourceRange bracketRange, VarDecl *capturedSelfDecl,
@@ -4083,11 +4081,8 @@ class ClosureExpr : public AbstractClosureExpr {
40834081
SourceLoc getEndLoc() const;
40844082
SourceLoc getLoc() const;
40854083

4086-
BraceStmt *getBody() const { return Body.getPointer(); }
4087-
void setBody(BraceStmt *S, bool isSingleExpression) {
4088-
Body.setPointer(S);
4089-
Body.setInt(isSingleExpression);
4090-
}
4084+
BraceStmt *getBody() const { return Body; }
4085+
void setBody(BraceStmt *S) { Body = S; }
40914086

40924087
DeclAttributes &getAttrs() { return Attributes; }
40934088
const DeclAttributes &getAttrs() const { return Attributes; }
@@ -4202,13 +4197,11 @@ class ClosureExpr : public AbstractClosureExpr {
42024197
/// ... even if the closure has been coerced to return Void by the type
42034198
/// checker. This function does not return true for empty closures.
42044199
bool hasSingleExpressionBody() const {
4205-
return Body.getInt();
4200+
return getSingleExpressionBody();
42064201
}
42074202

42084203
/// Retrieve the body for closure that has a single expression for
4209-
/// its body.
4210-
///
4211-
/// Only valid when \c hasSingleExpressionBody() is true.
4204+
/// its body, or \c nullptr if there is no single expression body.
42124205
Expr *getSingleExpressionBody() const;
42134206

42144207
/// Is this a completely empty closure?

include/swift/AST/Stmt.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ class alignas(8) Stmt : public ASTAllocated<Stmt> {
9999
: NumPadBits,
100100
CaseCount : 32
101101
);
102+
103+
SWIFT_INLINE_BITFIELD(ReturnStmt, Stmt, 1,
104+
/// Whether the result is an implied return, e.g for an implicit single
105+
/// expression return.
106+
IsImplied : 1
107+
);
102108

103109
SWIFT_INLINE_BITFIELD_FULL(YieldStmt, Stmt, 32,
104110
: NumPadBits,
@@ -244,7 +250,9 @@ class ReturnStmt : public Stmt {
244250

245251
ReturnStmt(SourceLoc returnLoc, Expr *result, bool isImplicit)
246252
: Stmt(StmtKind::Return, isImplicit), ReturnLoc(returnLoc),
247-
Result(result) {}
253+
Result(result) {
254+
Bits.ReturnStmt.IsImplied = false;
255+
}
248256

249257
public:
250258
static ReturnStmt *createParsed(ASTContext &ctx, SourceLoc returnLoc,
@@ -261,11 +269,25 @@ class ReturnStmt : public Stmt {
261269
return createImplicit(ctx, SourceLoc(), result);
262270
}
263271

272+
/// Create an implicit implied ReturnStmt for a single expression body.
273+
static ReturnStmt *forSingleExprBody(ASTContext &ctx, Expr *result) {
274+
assert(result && "Result must be present to be implied");
275+
auto *RS = createImplicit(ctx, result);
276+
RS->Bits.ReturnStmt.IsImplied = true;
277+
return RS;
278+
}
279+
264280
SourceLoc getReturnLoc() const { return ReturnLoc; }
265281

266282
SourceLoc getStartLoc() const;
267283
SourceLoc getEndLoc() const;
268284

285+
/// Whether the result is an implied return, e.g for an implicit single
286+
/// expression return.
287+
bool isImplied() const {
288+
return Bits.ReturnStmt.IsImplied;
289+
}
290+
269291
bool hasResult() const { return Result != 0; }
270292
Expr *getResult() const {
271293
assert(Result && "ReturnStmt doesn't have a result");

include/swift/Sema/ConstraintLocator.h

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,17 @@ class ProtocolConformance;
4747
/// specified error messages when the conversion fails.
4848
///
4949
enum ContextualTypePurpose : uint8_t {
50-
CTP_Unused, ///< No contextual type is specified.
51-
CTP_Initialization, ///< Pattern binding initialization.
52-
CTP_ReturnStmt, ///< Value specified to a 'return' statement.
53-
CTP_ReturnSingleExpr, ///< Value implicitly returned from a function.
54-
CTP_YieldByValue, ///< By-value yield operand.
55-
CTP_YieldByReference, ///< By-reference yield operand.
56-
CTP_ThrowStmt, ///< Value specified to a 'throw' statement.
57-
CTP_DiscardStmt, ///< Value specified to a 'discard' statement.
58-
CTP_EnumCaseRawValue, ///< Raw value specified for "case X = 42" in enum.
59-
CTP_DefaultParameter, ///< Default value in parameter 'foo(a : Int = 42)'.
50+
CTP_Unused, ///< No contextual type is specified.
51+
CTP_Initialization, ///< Pattern binding initialization.
52+
CTP_ReturnStmt, ///< Value specified to a 'return' statement.
53+
CTP_ImpliedReturnStmt, ///< Value from an implied 'return', e.g a single expr
54+
/// function body.
55+
CTP_YieldByValue, ///< By-value yield operand.
56+
CTP_YieldByReference, ///< By-reference yield operand.
57+
CTP_ThrowStmt, ///< Value specified to a 'throw' statement.
58+
CTP_DiscardStmt, ///< Value specified to a 'discard' statement.
59+
CTP_EnumCaseRawValue, ///< Raw value specified for "case X = 42" in enum.
60+
CTP_DefaultParameter, ///< Default value in parameter 'foo(a : Int = 42)'.
6061

6162
/// Default value in @autoclosure parameter
6263
/// 'foo(a : @autoclosure () -> Int = 42)'.
@@ -819,11 +820,13 @@ class LocatorPathElt::TypeParameterRequirement final
819820

820821
class LocatorPathElt::ClosureBody final : public StoredIntegerElement<1> {
821822
public:
822-
ClosureBody(bool hasExplicitReturn = false)
823-
: StoredIntegerElement(ConstraintLocator::ClosureBody, hasExplicitReturn) {}
823+
ClosureBody(bool hasImpliedReturn)
824+
: StoredIntegerElement(ConstraintLocator::ClosureBody, hasImpliedReturn) {}
824825

825-
/// Indicates whether body of the closure has any `return` statements.
826-
bool hasExplicitReturn() const { return bool(getValue()); }
826+
/// Indicates whether body of the closure has an implied `return` statement,
827+
/// this is the case for single expression bodies where the `return` was not
828+
/// written explicitly.
829+
bool hasImpliedReturn() const { return bool(getValue()); }
827830

828831
static bool classof(const LocatorPathElt *elt) {
829832
return elt->getKind() == ConstraintLocator::ClosureBody;

lib/AST/ASTBridging.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ BridgedClosureExpr_createParsed(BridgedASTContext cContext,
10191019
auto *out = new (context) ClosureExpr(
10201020
attributes, bracketRange, nullptr, nullptr, asyncLoc, throwsLoc,
10211021
/*FIXME:thrownType=*/nullptr, arrowLoc, inLoc, nullptr, declContext);
1022-
out->setBody(body.unbridged(), /*isSingleExpression*/ false);
1022+
out->setBody(body.unbridged());
10231023
out->setParameterList(params);
10241024
return out;
10251025
}

lib/AST/ASTWalker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
10191019

10201020
// Handle other closures.
10211021
if (BraceStmt *body = cast_or_null<BraceStmt>(doIt(expr->getBody()))) {
1022-
expr->setBody(body, expr->hasSingleExpressionBody());
1022+
expr->setBody(body);
10231023
return expr;
10241024
}
10251025
return nullptr;

lib/AST/Expr.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2034,18 +2034,28 @@ swift::__AbstractClosureExpr_getActorIsolation(AbstractClosureExpr *CE) {
20342034
return (NODE)->getStartLoc(); \
20352035
}
20362036

2037-
FORWARD_SOURCE_LOCS_TO(ClosureExpr, Body.getPointer())
2037+
FORWARD_SOURCE_LOCS_TO(ClosureExpr, Body)
20382038

20392039
Expr *ClosureExpr::getSingleExpressionBody() const {
2040-
assert(hasSingleExpressionBody() && "Not a single-expression body");
2041-
auto body = getBody()->getLastElement();
2042-
if (auto stmt = body.dyn_cast<Stmt *>()) {
2043-
if (auto braceStmt = dyn_cast<BraceStmt>(stmt))
2044-
return braceStmt->getLastElement().get<Expr *>();
2040+
auto *body = getBody();
2041+
if (!body)
2042+
return nullptr;
20452043

2046-
return cast<ReturnStmt>(stmt)->getResult();
2047-
}
2048-
return body.get<Expr *>();
2044+
// If we have a lone expression, use it.
2045+
if (auto *E = body->getSingleActiveExpression())
2046+
return E;
2047+
2048+
// Otherwise we must have a return of an expression.
2049+
auto elt = body->getSingleActiveStatement();
2050+
if (!elt)
2051+
return nullptr;
2052+
2053+
// Any lone ReturnStmt, even explicit, is treated as a single expression body.
2054+
auto *RS = dyn_cast<ReturnStmt>(elt);
2055+
if (!RS || !RS->hasResult())
2056+
return nullptr;
2057+
2058+
return RS->getResult();
20492059
}
20502060

20512061
bool ClosureExpr::hasEmptyBody() const {

lib/IDE/TypeCheckCompletionCallback.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ bool swift::ide::isImplicitSingleExpressionReturn(ConstraintSystem &CS,
159159
Expr *CompletionExpr) {
160160
Expr *ParentExpr = CS.getParentExpr(CompletionExpr);
161161
if (!ParentExpr)
162-
return CS.getContextualTypePurpose(CompletionExpr) == CTP_ReturnSingleExpr;
162+
return CS.getContextualTypePurpose(CompletionExpr) == CTP_ImpliedReturnStmt;
163163

164164
if (auto *ParentCE = dyn_cast<ClosureExpr>(ParentExpr)) {
165165
if (ParentCE->hasSingleExpressionBody() &&

lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8814,15 +8814,14 @@ Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) {
88148814
SourceLoc LBraceLoc, RBraceLoc;
88158815
LBraceLoc = consumeToken(tok::l_brace);
88168816
auto *CCE = new (Context) CodeCompletionExpr(Tok.getLoc());
8817-
auto *Return = ReturnStmt::createImplicit(Context, CCE);
8817+
auto *Return = ReturnStmt::forSingleExprBody(Context, CCE);
88188818
CodeCompletionCallbacks->setParsedDecl(accessor);
88198819
CodeCompletionCallbacks->completeAccessorBeginning(CCE);
88208820
RBraceLoc = Tok.getLoc();
88218821
consumeToken(tok::code_complete);
88228822
auto *BS =
88238823
BraceStmt::create(Context, LBraceLoc, ASTNode(Return), RBraceLoc,
88248824
/*implicit*/ true);
8825-
AFD->setHasSingleExpressionBody();
88268825
AFD->setBodyParsed(BS);
88278826
return {BS, Fingerprint::ZERO()};
88288827
}

0 commit comments

Comments
 (0)