Skip to content

Commit d8b745d

Browse files
committed
Add a request to lazily parse function bodies.
Rework the lazy function body parsing mechanism to use the request-evaluator, so that asking for the body of a function will initiate parsing. Clean up a number of callers to AbstractFunctionDecl::getBody() that don't actually need the body, so we don't perform unnecessary parsing. This change does not delay parsing of function bodies in the general case; rather, it sets up the infrastructure to always delay parsing of function bodies.
1 parent 1cd5d2e commit d8b745d

15 files changed

+161
-93
lines changed

include/swift/AST/Decl.h

+2
Original file line numberDiff line numberDiff line change
@@ -5594,6 +5594,8 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
55945594
SourceRange BodyRange;
55955595
};
55965596

5597+
friend class ParseAbstractFunctionBodyRequest;
5598+
55975599
CaptureInfo Captures;
55985600

55995601
/// Location of the 'throws' token.

include/swift/AST/ParseRequests.h

+22
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,28 @@ class ParseMembersRequest :
4848
bool isCached() const { return true; }
4949
};
5050

51+
/// Parse the body of a function, initializer, or deinitializer.
52+
class ParseAbstractFunctionBodyRequest :
53+
public SimpleRequest<ParseAbstractFunctionBodyRequest,
54+
BraceStmt *(AbstractFunctionDecl *),
55+
CacheKind::SeparatelyCached>
56+
{
57+
public:
58+
using SimpleRequest::SimpleRequest;
59+
60+
private:
61+
friend SimpleRequest;
62+
63+
// Evaluation.
64+
BraceStmt *evaluate(Evaluator &evaluator, AbstractFunctionDecl *afd) const;
65+
66+
public:
67+
// Caching
68+
bool isCached() const { return true; }
69+
Optional<BraceStmt *> getCachedResult() const;
70+
void cacheResult(BraceStmt *value) const;
71+
};
72+
5173
/// The zone number for the parser.
5274
#define SWIFT_TYPEID_ZONE Parse
5375
#define SWIFT_TYPEID_HEADER "swift/AST/ParseTypeIDZone.def"

include/swift/AST/ParseTypeIDZone.def

+1
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
SWIFT_REQUEST(Parse, ParseMembersRequest)
18+
SWIFT_REQUEST(Parse, ParseAbstractFunctionBodyRequest)

include/swift/Parse/Parser.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1124,7 +1124,7 @@ class Parser {
11241124
DeclAttributes &Attributes,
11251125
bool HasFuncKeyword = true);
11261126
void parseAbstractFunctionBody(AbstractFunctionDecl *AFD);
1127-
bool parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD);
1127+
BraceStmt *parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD);
11281128
ParserResult<ProtocolDecl> parseDeclProtocol(ParseDeclOptions Flags,
11291129
DeclAttributes &Attributes);
11301130

include/swift/Parse/PersistentParserState.h

-8
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,6 @@ class PersistentParserState {
109109
PersistentParserState(ASTContext &ctx) : PersistentParserState() { }
110110
~PersistentParserState();
111111

112-
void delayFunctionBodyParsing(AbstractFunctionDecl *AFD,
113-
SourceRange BodyRange,
114-
SourceLoc PreviousLoc);
115-
std::unique_ptr<FunctionBodyState>
116-
takeFunctionBodyState(AbstractFunctionDecl *AFD);
117-
118-
bool hasFunctionBodyState(AbstractFunctionDecl *AFD);
119-
120112
void delayDecl(DelayedDeclKind Kind, unsigned Flags,
121113
DeclContext *ParentContext,
122114
SourceRange BodyRange, SourceLoc PreviousLoc);

lib/AST/ASTPrinter.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,13 @@ PrintOptions PrintOptions::printParseableInterfaceFile(bool preferTypeRepr) {
118118

119119
result.FunctionBody = [](const ValueDecl *decl, ASTPrinter &printer) {
120120
auto AFD = dyn_cast<AbstractFunctionDecl>(decl);
121-
if (!AFD || !AFD->hasInlinableBodyText()) return;
121+
if (!AFD)
122+
return;
122123
if (AFD->getResilienceExpansion() != ResilienceExpansion::Minimal)
123124
return;
125+
if (!AFD->hasInlinableBodyText())
126+
return;
127+
124128
SmallString<128> scratch;
125129
printer << " " << AFD->getInlinableBodyText(scratch);
126130
};

lib/AST/ASTScopeCreation.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -1272,7 +1272,7 @@ void AbstractFunctionDeclScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
12721272
// Create scope for the body.
12731273
// We create body scopes when there is no body for source kit to complete
12741274
// erroneous code in bodies. But don't let compiler synthesize one.
1275-
if (decl->getBody(false) && decl->getBodySourceRange().isValid()) {
1275+
if (decl->getBodySourceRange().isValid() && decl->getBody(false)) {
12761276
if (AbstractFunctionBodyScope::isAMethod(decl))
12771277
scopeCreator.constructExpandAndInsertUncheckable<MethodBodyScope>(leaf,
12781278
decl);
@@ -1771,10 +1771,10 @@ bool IterableTypeScope::isBodyCurrent() const {
17711771
}
17721772

17731773
void AbstractFunctionBodyScope::beCurrent() {
1774-
bodyWhenLastExpanded = decl->getBody();
1774+
bodyWhenLastExpanded = decl->getBody(false);
17751775
}
17761776
bool AbstractFunctionBodyScope::isCurrent() const {
1777-
return bodyWhenLastExpanded == decl->getBody();
1777+
return bodyWhenLastExpanded == decl->getBody(false);
17781778
;
17791779
}
17801780

lib/AST/Decl.cpp

+64-28
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "swift/AST/NameLookup.h"
3434
#include "swift/AST/NameLookupRequests.h"
3535
#include "swift/AST/ParameterList.h"
36+
#include "swift/AST/ParseRequests.h"
3637
#include "swift/AST/Pattern.h"
3738
#include "swift/AST/PropertyWrappers.h"
3839
#include "swift/AST/ProtocolConformance.h"
@@ -6307,37 +6308,22 @@ bool AbstractFunctionDecl::argumentNameIsAPIByDefault() const {
63076308
}
63086309

63096310
BraceStmt *AbstractFunctionDecl::getBody(bool canSynthesize) const {
6310-
switch (getBodyKind()) {
6311-
case BodyKind::Deserialized:
6312-
case BodyKind::MemberwiseInitializer:
6313-
case BodyKind::None:
6314-
case BodyKind::Skipped:
6311+
if ((getBodyKind() == BodyKind::Synthesize ||
6312+
getBodyKind() == BodyKind::Unparsed) &&
6313+
!canSynthesize)
63156314
return nullptr;
63166315

6317-
case BodyKind::Parsed:
6318-
case BodyKind::TypeChecked:
6319-
return Body;
6316+
ASTContext &ctx = getASTContext();
63206317

6321-
case BodyKind::Unparsed:
6322-
// FIXME: Go parse now!
6318+
// Don't allow getBody() to trigger parsing of an unparsed body containing the
6319+
// code completion location.
6320+
if (getBodyKind() == BodyKind::Unparsed &&
6321+
ctx.SourceMgr.rangeContainsCodeCompletionLoc(getBodySourceRange())) {
63236322
return nullptr;
6324-
6325-
case BodyKind::Synthesize: {
6326-
if (!canSynthesize)
6327-
return nullptr;
6328-
6329-
const_cast<AbstractFunctionDecl *>(this)->setBodyKind(BodyKind::None);
6330-
BraceStmt *body;
6331-
bool isTypeChecked;
6332-
6333-
auto mutableThis = const_cast<AbstractFunctionDecl *>(this);
6334-
std::tie(body, isTypeChecked) = (Synthesizer.Fn)(
6335-
mutableThis, Synthesizer.Context);
6336-
mutableThis->setBody(
6337-
body, isTypeChecked ? BodyKind::TypeChecked : BodyKind::Parsed);
6338-
return body;
6339-
}
63406323
}
6324+
6325+
auto mutableThis = const_cast<AbstractFunctionDecl *>(this);
6326+
return evaluateOrDefault(ctx.evaluator, ParseAbstractFunctionBodyRequest{mutableThis}, nullptr);
63416327
}
63426328

63436329
SourceRange AbstractFunctionDecl::getBodySourceRange() const {
@@ -6804,11 +6790,15 @@ bool AbstractFunctionDecl::hasInlinableBodyText() const {
68046790
switch (getBodyKind()) {
68056791
case BodyKind::Deserialized:
68066792
return true;
6793+
6794+
case BodyKind::Unparsed:
68076795
case BodyKind::Parsed:
68086796
case BodyKind::TypeChecked:
6809-
return getBody() && !getBody()->isImplicit();
6797+
if (auto body = getBody())
6798+
return !body->isImplicit();
6799+
return false;
6800+
68106801
case BodyKind::None:
6811-
case BodyKind::Unparsed:
68126802
case BodyKind::Synthesize:
68136803
case BodyKind::Skipped:
68146804
case BodyKind::MemberwiseInitializer:
@@ -7676,3 +7666,49 @@ SourceLoc swift::extractNearestSourceLoc(const Decl *decl) {
76767666

76777667
return extractNearestSourceLoc(decl->getDeclContext());
76787668
}
7669+
7670+
Optional<BraceStmt *>
7671+
ParseAbstractFunctionBodyRequest::getCachedResult() const {
7672+
using BodyKind = AbstractFunctionDecl::BodyKind;
7673+
auto afd = std::get<0>(getStorage());
7674+
switch (afd->getBodyKind()) {
7675+
case BodyKind::Deserialized:
7676+
case BodyKind::MemberwiseInitializer:
7677+
case BodyKind::None:
7678+
case BodyKind::Skipped:
7679+
return nullptr;
7680+
7681+
case BodyKind::TypeChecked:
7682+
case BodyKind::Parsed:
7683+
return afd->Body;
7684+
7685+
case BodyKind::Synthesize:
7686+
case BodyKind::Unparsed:
7687+
return None;
7688+
}
7689+
}
7690+
7691+
void ParseAbstractFunctionBodyRequest::cacheResult(BraceStmt *value) const {
7692+
using BodyKind = AbstractFunctionDecl::BodyKind;
7693+
auto afd = std::get<0>(getStorage());
7694+
switch (afd->getBodyKind()) {
7695+
case BodyKind::Deserialized:
7696+
case BodyKind::MemberwiseInitializer:
7697+
case BodyKind::None:
7698+
case BodyKind::Skipped:
7699+
// The body is always empty, so don't cache anything.
7700+
assert(value == nullptr);
7701+
return;
7702+
7703+
case BodyKind::Parsed:
7704+
case BodyKind::TypeChecked:
7705+
afd->Body = value;
7706+
return;
7707+
7708+
case BodyKind::Synthesize:
7709+
case BodyKind::Unparsed:
7710+
llvm_unreachable("evaluate() did not set the body kind");
7711+
return;
7712+
}
7713+
7714+
}

lib/AST/UnqualifiedLookup.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@ void UnqualifiedLookupFactory::lookupNamesIntroducedByFunctionDecl(
663663
const bool isCascadingUse =
664664
AFD->isCascadingContextForLookup(false) &&
665665
(isCascadingUseArg.getValueOr(
666-
Loc.isInvalid() || !AFD->getBody() ||
666+
Loc.isInvalid() || AFD->getBodySourceRange().isInvalid() ||
667667
!SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc)));
668668

669669
if (AFD->getDeclContext()->isTypeContext())
@@ -814,7 +814,9 @@ void UnqualifiedLookupFactory::lookForLocalVariablesIn(
814814
// FIXME: when we can parse and typecheck the function body partially
815815
// for code completion, AFD->getBody() check can be removed.
816816

817-
if (Loc.isInvalid() || !AFD->getBody()) {
817+
if (Loc.isInvalid() || AFD->getBodySourceRange().isInvalid() ||
818+
!SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc) ||
819+
!AFD->getBody()) {
818820
return;
819821
}
820822

lib/Parse/ParseDecl.cpp

+6-19
Original file line numberDiff line numberDiff line change
@@ -5390,8 +5390,6 @@ void Parser::consumeAbstractFunctionBody(AbstractFunctionDecl *AFD,
53905390
if (DelayedParseCB &&
53915391
DelayedParseCB->shouldDelayFunctionBodyParsing(*this, AFD, Attrs,
53925392
BodyRange)) {
5393-
State->delayFunctionBodyParsing(AFD, BodyRange,
5394-
BeginParserPosition.PreviousLoc);
53955393
AFD->setBodyDelayed(BodyRange);
53965394
} else {
53975395
AFD->setBodySkipped(BodyRange);
@@ -5672,15 +5670,12 @@ void Parser::parseAbstractFunctionBody(AbstractFunctionDecl *AFD) {
56725670
}
56735671
}
56745672

5675-
bool Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) {
5676-
assert(!AFD->getBody() && "function should not have a parsed body");
5673+
BraceStmt *Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) {
56775674
assert(AFD->getBodyKind() == AbstractFunctionDecl::BodyKind::Unparsed &&
56785675
"function body should be delayed");
56795676

5680-
auto FunctionParserState = State->takeFunctionBodyState(AFD);
5681-
assert(FunctionParserState.get() && "should have a valid state");
5682-
5683-
auto BeginParserPosition = getParserPosition(FunctionParserState->BodyPos);
5677+
auto bodyRange = AFD->getBodySourceRange();
5678+
auto BeginParserPosition = getParserPosition({bodyRange.Start,bodyRange.End});
56845679
auto EndLexerState = L->getStateForEndOfTokenLoc(AFD->getEndLoc());
56855680

56865681
// ParserPositionRAII needs a primed parser to restore to.
@@ -5700,20 +5695,12 @@ bool Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) {
57005695
restoreParserPosition(BeginParserPosition);
57015696

57025697
// Re-enter the lexical scope.
5703-
Scope S(this, FunctionParserState->takeScope());
5698+
Scope TopLevelScope(this, ScopeKind::TopLevel);
5699+
Scope S(this, ScopeKind::FunctionBody);
57045700
ParseFunctionBody CC(*this, AFD);
57055701
setLocalDiscriminatorToParamList(AFD->getParameters());
57065702

5707-
ParserResult<BraceStmt> Body =
5708-
parseBraceItemList(diag::func_decl_without_brace);
5709-
if (Body.isNull()) {
5710-
// FIXME: Should do some sort of error recovery here?
5711-
return true;
5712-
} else {
5713-
AFD->setBodyParsed(Body.get());
5714-
}
5715-
5716-
return false;
5703+
return parseBraceItemList(diag::func_decl_without_brace).getPtrOrNull();
57175704
}
57185705

57195706
/// Parse a 'enum' declaration, returning true (and doing no token

lib/Parse/ParseRequests.cpp

+44
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,50 @@ ParseMembersRequest::evaluate(Evaluator &evaluator,
4848
llvm::makeArrayRef(parser.parseDeclListDelayed(idc)));
4949
}
5050

51+
BraceStmt *ParseAbstractFunctionBodyRequest::evaluate(
52+
Evaluator &evaluator, AbstractFunctionDecl *afd) const {
53+
using BodyKind = AbstractFunctionDecl::BodyKind;
54+
55+
switch (afd->getBodyKind()) {
56+
case BodyKind::Deserialized:
57+
case BodyKind::MemberwiseInitializer:
58+
case BodyKind::None:
59+
case BodyKind::Skipped:
60+
return nullptr;
61+
62+
case BodyKind::TypeChecked:
63+
case BodyKind::Parsed:
64+
return afd->Body;
65+
66+
case BodyKind::Synthesize: {
67+
BraceStmt *body;
68+
bool isTypeChecked;
69+
70+
std::tie(body, isTypeChecked) = (afd->Synthesizer.Fn)(
71+
afd, afd->Synthesizer.Context);
72+
afd->setBodyKind(isTypeChecked ? BodyKind::TypeChecked : BodyKind::Parsed);
73+
return body;
74+
}
75+
76+
case BodyKind::Unparsed: {
77+
// FIXME: It should be fine to delay body parsing of local functions, so
78+
// the DelayBodyParsing should go away entirely
79+
// FIXME: How do we configure code completion?
80+
SourceFile &sf = *afd->getDeclContext()->getParentSourceFile();
81+
SourceManager &sourceMgr = sf.getASTContext().SourceMgr;
82+
unsigned bufferID = sourceMgr.findBufferContainingLoc(afd->getLoc());
83+
Parser parser(bufferID, sf, nullptr, nullptr, nullptr,
84+
/*DelayBodyParsing=*/false);
85+
parser.SyntaxContext->setDiscard();
86+
auto body = parser.parseAbstractFunctionBodyDelayed(afd);
87+
afd->setBodyKind(BodyKind::Parsed);
88+
return body;
89+
}
90+
}
91+
92+
}
93+
94+
5195
// Define request evaluation functions for each of the type checker requests.
5296
static AbstractRequestFunction *parseRequestFunctions[] = {
5397
#define SWIFT_REQUEST(Zone, Name) \

lib/Parse/Parser.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ class ParseDelayedFunctionBodies : public ASTWalker {
138138

139139
private:
140140
void parseFunctionBody(AbstractFunctionDecl *AFD) {
141+
// FIXME: This duplicates the evaluation of
142+
// ParseAbstractFunctionBodyRequest, but installs a code completion
143+
// factory.
141144
assert(AFD->getBodyKind() == FuncDecl::BodyKind::Unparsed);
142145

143146
SourceFile &SF = *AFD->getDeclContext()->getParentSourceFile();
@@ -152,8 +155,8 @@ class ParseDelayedFunctionBodies : public ASTWalker {
152155
CodeCompletionFactory->createCodeCompletionCallbacks(TheParser));
153156
TheParser.setCodeCompletionCallbacks(CodeCompletion.get());
154157
}
155-
if (ParserState.hasFunctionBodyState(AFD))
156-
TheParser.parseAbstractFunctionBodyDelayed(AFD);
158+
auto body = TheParser.parseAbstractFunctionBodyDelayed(AFD);
159+
AFD->setBodyParsed(body);
157160

158161
if (CodeCompletion)
159162
CodeCompletion->doneParsing();

0 commit comments

Comments
 (0)