Skip to content

Commit 097b1b4

Browse files
authored
Merge pull request #26981 from DougGregor/request-function-body-parse-again
Add a request to lazily parse function bodies.
2 parents 9022437 + 9249966 commit 097b1b4

18 files changed

+173
-126
lines changed

include/swift/AST/Decl.h

Lines changed: 2 additions & 0 deletions
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

Lines changed: 22 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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/Basic/SourceManager.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@ class SourceManager {
103103
rangeContainsTokenLoc(Enclosing, Inner.End);
104104
}
105105

106+
/// Returns true if range \p R contains the code-completion location, if any.
107+
bool rangeContainsCodeCompletionLoc(SourceRange R) const {
108+
return CodeCompletionBufferID
109+
? rangeContainsTokenLoc(R, getCodeCompletionLoc())
110+
: false;
111+
}
112+
106113
/// Returns the buffer ID for the specified *valid* location.
107114
///
108115
/// Because a valid source location always corresponds to a source buffer,

include/swift/Parse/Parser.h

Lines changed: 1 addition & 1 deletion
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

Lines changed: 0 additions & 8 deletions
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);

include/swift/Sema/SourceLoader.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,20 @@ class ModuleDecl;
2424
class SourceLoader : public ModuleLoader {
2525
private:
2626
ASTContext &Ctx;
27-
bool SkipBodies;
2827
bool EnableLibraryEvolution;
2928

3029
explicit SourceLoader(ASTContext &ctx,
31-
bool skipBodies,
3230
bool enableResilience,
3331
DependencyTracker *tracker)
3432
: ModuleLoader(tracker), Ctx(ctx),
35-
SkipBodies(skipBodies), EnableLibraryEvolution(enableResilience) {}
33+
EnableLibraryEvolution(enableResilience) {}
3634

3735
public:
3836
static std::unique_ptr<SourceLoader>
39-
create(ASTContext &ctx, bool skipBodies, bool enableResilience,
37+
create(ASTContext &ctx, bool enableResilience,
4038
DependencyTracker *tracker = nullptr) {
4139
return std::unique_ptr<SourceLoader>{
42-
new SourceLoader(ctx, skipBodies, enableResilience, tracker)
40+
new SourceLoader(ctx, enableResilience, tracker)
4341
};
4442
}
4543

lib/AST/ASTPrinter.cpp

Lines changed: 5 additions & 1 deletion
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

Lines changed: 3 additions & 3 deletions
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

Lines changed: 64 additions & 28 deletions
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

Lines changed: 4 additions & 2 deletions
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/Frontend/Frontend.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -315,12 +315,9 @@ void CompilerInstance::setUpDiagnosticOptions() {
315315

316316
bool CompilerInstance::setUpModuleLoaders() {
317317
if (hasSourceImport()) {
318-
bool immediate = FrontendOptions::isActionImmediate(
319-
Invocation.getFrontendOptions().RequestedAction);
320318
bool enableLibraryEvolution =
321319
Invocation.getFrontendOptions().EnableLibraryEvolution;
322320
Context->addModuleLoader(SourceLoader::create(*Context,
323-
!immediate,
324321
enableLibraryEvolution,
325322
getDependencyTracker()));
326323
}

lib/Parse/ParseDecl.cpp

Lines changed: 6 additions & 19 deletions
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

0 commit comments

Comments
 (0)