Skip to content

Commit c26eb11

Browse files
authored
Merge pull request swiftlang#30190 from hamishknight/the-beginning-of-the-pipeline-end
Requestify SourceFile parsing
2 parents cf451c2 + df34be7 commit c26eb11

21 files changed

+235
-147
lines changed

include/swift/AST/ParseRequests.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,27 @@ class ParseAbstractFunctionBodyRequest :
8080
void cacheResult(BraceStmt *value) const;
8181
};
8282

83+
/// Parse the top-level decls of a SourceFile.
84+
class ParseSourceFileRequest
85+
: public SimpleRequest<ParseSourceFileRequest,
86+
ArrayRef<Decl *>(SourceFile *),
87+
CacheKind::SeparatelyCached> {
88+
public:
89+
using SimpleRequest::SimpleRequest;
90+
91+
private:
92+
friend SimpleRequest;
93+
94+
// Evaluation.
95+
ArrayRef<Decl *> evaluate(Evaluator &evaluator, SourceFile *SF) const;
96+
97+
public:
98+
// Caching.
99+
bool isCached() const { return true; }
100+
Optional<ArrayRef<Decl *>> getCachedResult() const;
101+
void cacheResult(ArrayRef<Decl *> decls) const;
102+
};
103+
83104
/// The zone number for the parser.
84105
#define SWIFT_TYPEID_ZONE Parse
85106
#define SWIFT_TYPEID_HEADER "swift/AST/ParseTypeIDZone.def"

include/swift/AST/ParseTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,6 @@ SWIFT_REQUEST(Parse, ParseMembersRequest,
1919
SWIFT_REQUEST(Parse, ParseAbstractFunctionBodyRequest,
2020
BraceStmt *(AbstractFunctionDecl *), SeparatelyCached,
2121
NoLocationInfo)
22+
SWIFT_REQUEST(Parse, ParseSourceFileRequest,
23+
ArrayRef<Decl *>(SourceFile *), SeparatelyCached,
24+
NoLocationInfo)

include/swift/AST/SourceFile.h

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ class PersistentParserState;
2727
/// before being used for anything; a full type-check is also necessary for
2828
/// IR generation.
2929
class SourceFile final : public FileUnit {
30+
friend class ParseSourceFileRequest;
31+
3032
public:
3133
class Impl;
3234
struct SourceFileSyntaxInfo;
@@ -175,8 +177,11 @@ class SourceFile final : public FileUnit {
175177
/// been validated.
176178
llvm::SetVector<ValueDecl *> UnvalidatedDeclsWithOpaqueReturnTypes;
177179

178-
/// The list of top-level declarations in the source file.
179-
std::vector<Decl *> Decls;
180+
/// The list of top-level declarations in the source file. This is \c None if
181+
/// they have not yet been parsed.
182+
/// FIXME: Once addTopLevelDecl/prependTopLevelDecl/truncateTopLevelDecls
183+
/// have been removed, this can become an optional ArrayRef.
184+
Optional<std::vector<Decl *>> Decls;
180185

181186
using SeparatelyImportedOverlayMap =
182187
llvm::SmallDenseMap<ModuleDecl *, llvm::SmallPtrSet<ModuleDecl *, 1>>;
@@ -203,9 +208,12 @@ class SourceFile final : public FileUnit {
203208
friend Impl;
204209

205210
public:
206-
/// Appends the given declaration to the end of the top-level decls list.
211+
/// Appends the given declaration to the end of the top-level decls list. Do
212+
/// not add any additional uses of this function.
207213
void addTopLevelDecl(Decl *d) {
208-
Decls.push_back(d);
214+
// Force decl parsing if we haven't already.
215+
(void)getTopLevelDecls();
216+
Decls->push_back(d);
209217
}
210218

211219
/// Prepends a declaration to the top-level decls list.
@@ -215,18 +223,29 @@ class SourceFile final : public FileUnit {
215223
///
216224
/// See rdar://58355191
217225
void prependTopLevelDecl(Decl *d) {
218-
Decls.insert(Decls.begin(), d);
226+
// Force decl parsing if we haven't already.
227+
(void)getTopLevelDecls();
228+
Decls->insert(Decls->begin(), d);
219229
}
220230

221231
/// Retrieves an immutable view of the list of top-level decls in this file.
222-
ArrayRef<Decl *> getTopLevelDecls() const {
223-
return Decls;
232+
ArrayRef<Decl *> getTopLevelDecls() const;
233+
234+
/// Retrieves an immutable view of the top-level decls if they have already
235+
/// been parsed, or \c None if they haven't. Should only be used for dumping.
236+
Optional<ArrayRef<Decl *>> getCachedTopLevelDecls() const {
237+
if (!Decls)
238+
return None;
239+
return llvm::makeArrayRef(*Decls);
224240
}
225241

226-
/// Truncates the list of top-level decls so it contains \c count elements.
242+
/// Truncates the list of top-level decls so it contains \c count elements. Do
243+
/// not add any additional uses of this function.
227244
void truncateTopLevelDecls(unsigned count) {
228-
assert(count <= Decls.size() && "Can only truncate top-level decls!");
229-
Decls.resize(count);
245+
// Force decl parsing if we haven't already.
246+
(void)getTopLevelDecls();
247+
assert(count <= Decls->size() && "Can only truncate top-level decls!");
248+
Decls->resize(count);
230249
}
231250

232251
/// Retrieve the parsing options for the file.
@@ -287,10 +306,8 @@ class SourceFile final : public FileUnit {
287306
const SourceFileKind Kind;
288307

289308
enum ASTStage_t {
290-
/// Parsing is underway.
291-
Parsing,
292-
/// Parsing has completed.
293-
Parsed,
309+
/// The source file is not name bound or type checked.
310+
Unprocessed,
294311
/// Name binding has completed.
295312
NameBound,
296313
/// Type checking has completed.
@@ -302,7 +319,7 @@ class SourceFile final : public FileUnit {
302319
///
303320
/// Only files that have been fully processed (i.e. type-checked) will be
304321
/// forwarded on to IRGen.
305-
ASTStage_t ASTStage = Parsing;
322+
ASTStage_t ASTStage = Unprocessed;
306323

307324
SourceFile(ModuleDecl &M, SourceFileKind K, Optional<unsigned> bufferID,
308325
ImplicitModuleImportKind ModImpKind, bool KeepParsedTokens = false,
@@ -456,6 +473,13 @@ class SourceFile final : public FileUnit {
456473
/// Retrieves the previously set delayed parser state, asserting that it
457474
/// exists.
458475
PersistentParserState *getDelayedParserState() {
476+
// Force parsing of the top-level decls, which will set DelayedParserState
477+
// if necessary.
478+
// FIXME: Ideally the parser state should be an output of
479+
// ParseSourceFileRequest, but the evaluator doesn't currently support
480+
// move-only outputs for cached requests.
481+
(void)getTopLevelDecls();
482+
459483
auto *state = DelayedParserState.get();
460484
assert(state && "Didn't set any delayed parser state!");
461485
return state;

include/swift/Parse/ParseSILSupport.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,6 @@ namespace swift {
3737
virtual bool parseSILProperty(Parser &P) = 0;
3838
virtual bool parseSILScope(Parser &P) = 0;
3939
};
40-
41-
/// To assist debugging parser crashes, tell us the location of the
42-
/// current token.
43-
class PrettyStackTraceParser : public llvm::PrettyStackTraceEntry {
44-
Parser &P;
45-
public:
46-
explicit PrettyStackTraceParser(Parser &P) : P(P) {}
47-
void print(llvm::raw_ostream &out) const override;
48-
};
4940
} // end namespace swift
5041

5142
#endif // SWIFT_PARSER_PARSESILSUPPORT_H

include/swift/Parse/Parser.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,17 @@ class Parser {
114114
DiagnosticEngine &Diags;
115115
SourceFile &SF;
116116
Lexer *L;
117-
SILParserTUStateBase *SIL; // Non-null when parsing a .sil file.
117+
SILParserTUStateBase *SIL; // Non-null when parsing SIL decls.
118118
PersistentParserState *State;
119119
std::unique_ptr<PersistentParserState> OwnedState;
120120
DeclContext *CurDeclContext;
121121
ASTContext &Context;
122122
CodeCompletionCallbacks *CodeCompletion = nullptr;
123123
std::vector<Located<std::vector<ParamDecl*>>> AnonClosureVars;
124124

125+
/// Tracks parsed decls that LLDB requires to be inserted at the top-level.
126+
std::vector<Decl *> ContextSwitchedTopLevelDecls;
127+
125128
NullablePtr<llvm::MD5> CurrentTokenHash;
126129
void recordTokenHash(const Token Tok) {
127130
if (!Tok.getText().empty())
@@ -881,8 +884,8 @@ class Parser {
881884
/// Returns true if the parser is at the start of a SIL decl.
882885
bool isStartOfSILDecl();
883886

884-
/// Parse the top-level Swift decls into the source file.
885-
void parseTopLevel();
887+
/// Parse the top-level Swift decls into the provided vector.
888+
void parseTopLevel(SmallVectorImpl<Decl *> &decls);
886889

887890
/// Parse the top-level SIL decls into the SIL module.
888891
void parseTopLevelSIL();
@@ -1728,6 +1731,15 @@ struct ParsedDeclName {
17281731
DeclNameRef formDeclNameRef(ASTContext &ctx) const;
17291732
};
17301733

1734+
/// To assist debugging parser crashes, tell us the location of the
1735+
/// current token.
1736+
class PrettyStackTraceParser : public llvm::PrettyStackTraceEntry {
1737+
Parser &P;
1738+
public:
1739+
explicit PrettyStackTraceParser(Parser &P) : P(P) {}
1740+
void print(llvm::raw_ostream &out) const override;
1741+
};
1742+
17311743
/// Parse a stringified Swift declaration name,
17321744
/// e.g. "Foo.translateBy(self:x:y:)".
17331745
ParsedDeclName parseDeclName(StringRef name) LLVM_READONLY;

include/swift/Subsystems.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,6 @@ namespace swift {
103103

104104
/// @}
105105

106-
/// Parse a single buffer into the given source file.
107-
///
108-
/// \param SF The file within the module being parsed.
109-
///
110-
/// \param BufferID The buffer to parse from.
111-
void parseIntoSourceFile(SourceFile &SF, unsigned BufferID);
112-
113106
/// Parse a source file's SIL declarations into a given SIL module.
114107
void parseSourceFileSIL(SourceFile &SF, SILParserState *sil);
115108

lib/AST/ASTDumper.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -781,13 +781,15 @@ namespace {
781781
PrintWithColorRAII(OS, ParenthesisColor) << '(';
782782
PrintWithColorRAII(OS, ASTNodeColor) << "source_file ";
783783
PrintWithColorRAII(OS, LocationColor) << '\"' << SF.getFilename() << '\"';
784-
785-
for (Decl *D : SF.getTopLevelDecls()) {
786-
if (D->isImplicit())
787-
continue;
788784

789-
OS << '\n';
790-
printRec(D);
785+
if (auto decls = SF.getCachedTopLevelDecls()) {
786+
for (Decl *D : *decls) {
787+
if (D->isImplicit())
788+
continue;
789+
790+
OS << '\n';
791+
printRec(D);
792+
}
791793
}
792794
PrintWithColorRAII(OS, ParenthesisColor) << ')';
793795
}

lib/AST/Module.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "swift/AST/ModuleLoader.h"
3333
#include "swift/AST/NameLookup.h"
3434
#include "swift/AST/ReferencedNameTracker.h"
35+
#include "swift/AST/ParseRequests.h"
3536
#include "swift/AST/PrettyStackTrace.h"
3637
#include "swift/AST/PrintOptions.h"
3738
#include "swift/AST/ProtocolConformance.h"
@@ -674,7 +675,8 @@ void ModuleDecl::getTopLevelDeclsWhereAttributesMatch(
674675
}
675676

676677
void SourceFile::getTopLevelDecls(SmallVectorImpl<Decl*> &Results) const {
677-
Results.append(Decls.begin(), Decls.end());
678+
auto decls = getTopLevelDecls();
679+
Results.append(decls.begin(), decls.end());
678680
}
679681

680682
void ModuleDecl::getPrecedenceGroups(
@@ -1190,7 +1192,14 @@ void ModuleDecl::getImportedModules(SmallVectorImpl<ImportedModule> &modules,
11901192
void
11911193
SourceFile::getImportedModules(SmallVectorImpl<ModuleDecl::ImportedModule> &modules,
11921194
ModuleDecl::ImportFilter filter) const {
1193-
assert(ASTStage >= Parsed || Kind == SourceFileKind::SIL);
1195+
// FIXME: Ideally we should assert that the file has been name bound before
1196+
// calling this function. However unfortunately that can cause issues for
1197+
// overlays which can depend on a Clang submodule for the underlying framework
1198+
// they are overlaying, which causes us to attempt to load the overlay again.
1199+
// We need to find a way to ensure that an overlay dependency with the same
1200+
// name as the overlay always loads the underlying Clang module. We currently
1201+
// handle this for a direct import from the overlay, but not when it happens
1202+
// through other imports.
11941203
assert(filter && "no imports requested?");
11951204
for (auto desc : Imports) {
11961205
ModuleDecl::ImportFilter requiredFilter;
@@ -1688,7 +1697,7 @@ void SourceFile::print(raw_ostream &OS, const PrintOptions &PO) {
16881697
void SourceFile::print(ASTPrinter &Printer, const PrintOptions &PO) {
16891698
std::set<DeclKind> MajorDeclKinds = {DeclKind::Class, DeclKind::Enum,
16901699
DeclKind::Extension, DeclKind::Protocol, DeclKind::Struct};
1691-
for (auto decl : Decls) {
1700+
for (auto decl : getTopLevelDecls()) {
16921701
if (!decl->shouldPrintInContext(PO))
16931702
continue;
16941703
// For a major decl, we print an empty line before it.
@@ -2024,6 +2033,13 @@ bool SourceFile::hasDelayedBodyParsing() const {
20242033
return true;
20252034
}
20262035

2036+
ArrayRef<Decl *> SourceFile::getTopLevelDecls() const {
2037+
auto &ctx = getASTContext();
2038+
auto *mutableThis = const_cast<SourceFile *>(this);
2039+
return evaluateOrDefault(ctx.evaluator, ParseSourceFileRequest{mutableThis},
2040+
{});
2041+
}
2042+
20272043
bool FileUnit::walk(ASTWalker &walker) {
20282044
SmallVector<Decl *, 64> Decls;
20292045
getTopLevelDecls(Decls);
@@ -2057,7 +2073,7 @@ bool FileUnit::walk(ASTWalker &walker) {
20572073
bool SourceFile::walk(ASTWalker &walker) {
20582074
llvm::SaveAndRestore<ASTWalker::ParentTy> SAR(walker.Parent,
20592075
getParentModule());
2060-
for (Decl *D : Decls) {
2076+
for (Decl *D : getTopLevelDecls()) {
20612077
#ifndef NDEBUG
20622078
PrettyStackTraceDecl debugStack("walking into decl", D);
20632079
#endif

lib/Frontend/Frontend.cpp

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -763,11 +763,7 @@ void CompilerInstance::performSema() {
763763
}
764764

765765
void CompilerInstance::performSemaUpTo(SourceFile::ASTStage_t LimitStage) {
766-
// FIXME: A lot of the logic in `performParseOnly` is a stripped-down version
767-
// of the logic in `performSemaUpTo`. We should try to unify them over time.
768-
if (LimitStage <= SourceFile::Parsed) {
769-
return performParseOnly();
770-
}
766+
assert(LimitStage > SourceFile::Unprocessed);
771767

772768
FrontendStatsTracer tracer(getStatsReporter(), "perform-sema");
773769

@@ -974,7 +970,7 @@ void CompilerInstance::parseLibraryFile(
974970
SourceFileKind::Library, implicitImports.kind, BufferID);
975971
addAdditionalInitialImportsTo(NextInput, implicitImports);
976972

977-
parseIntoSourceFile(*NextInput, BufferID);
973+
// Name binding will lazily trigger parsing of the file.
978974
performNameBinding(*NextInput);
979975
}
980976

@@ -1017,11 +1013,8 @@ void CompilerInstance::parseAndTypeCheckMainFileUpTo(
10171013
auto DidSuppressWarnings = Diags.getSuppressWarnings();
10181014
Diags.setSuppressWarnings(DidSuppressWarnings || !mainIsPrimary);
10191015

1020-
// Parse the Swift decls into the source file.
1021-
parseIntoSourceFile(MainFile, MainBufferID);
1022-
1023-
// For a primary, also perform type checking if needed. Otherwise, just do
1024-
// name binding.
1016+
// For a primary, perform type checking if needed. Otherwise, just do name
1017+
// binding.
10251018
if (mainIsPrimary && LimitStage >= SourceFile::TypeChecked) {
10261019
performTypeChecking(MainFile);
10271020
} else {
@@ -1142,17 +1135,18 @@ void CompilerInstance::performParseOnly(bool EvaluateConditionals,
11421135
SourceFileKind::Library, SourceFile::ImplicitModuleImportKind::None,
11431136
BufferID, parsingOpts);
11441137

1145-
parseIntoSourceFile(*NextInput, BufferID);
1138+
// Force the parsing of the top level decls.
1139+
(void)NextInput->getTopLevelDecls();
11461140
}
11471141

11481142
// Now parse the main file.
11491143
if (MainBufferID != NO_SUCH_BUFFER) {
11501144
SourceFile &MainFile =
11511145
MainModule->getMainSourceFile(Invocation.getSourceFileKind());
11521146
MainFile.SyntaxParsingCache = Invocation.getMainFileSyntaxParsingCache();
1153-
assert(MainBufferID == MainFile.getBufferID());
11541147

1155-
parseIntoSourceFile(MainFile, MainBufferID);
1148+
// Force the parsing of the top level decls.
1149+
(void)MainFile.getTopLevelDecls();
11561150
}
11571151

11581152
assert(Context->LoadedModules.size() == 1 &&

lib/IDE/CompletionInstance.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ bool CompletionInstance::performCachedOperaitonIfPossible(
199199
DiagnosticEngine tmpDiags(tmpSM);
200200
std::unique_ptr<ASTContext> tmpCtx(
201201
ASTContext::get(langOpts, typeckOpts, searchPathOpts, tmpSM, tmpDiags));
202+
registerParseRequestFunctions(tmpCtx->evaluator);
202203
registerIDERequestFunctions(tmpCtx->evaluator);
203204
registerTypeCheckerRequestFunctions(tmpCtx->evaluator);
204205
registerSILGenRequestFunctions(tmpCtx->evaluator);
@@ -209,7 +210,6 @@ bool CompletionInstance::performCachedOperaitonIfPossible(
209210
tmpSF->enableInterfaceHash();
210211
// Ensure all non-function-body tokens are hashed into the interface hash
211212
tmpCtx->LangOpts.EnableTypeFingerprints = false;
212-
parseIntoSourceFile(*tmpSF, tmpBufferID);
213213

214214
// Couldn't find any completion token?
215215
auto *newState = tmpSF->getDelayedParserState();
@@ -324,8 +324,8 @@ bool CompletionInstance::performCachedOperaitonIfPossible(
324324
// Tell the compiler instance we've replaced the code completion file.
325325
CI.setCodeCompletionFile(newSF);
326326

327-
// Re-parse the whole file. Still re-use imported modules.
328-
parseIntoSourceFile(*newSF, newBufferID);
327+
// Re-process the whole file (parsing will be lazily triggered). Still
328+
// re-use imported modules.
329329
performNameBinding(*newSF);
330330
bindExtensions(*newSF);
331331

0 commit comments

Comments
 (0)