Skip to content

Commit d77cae6

Browse files
committed
Move PersistentParserState onto SourceFile
Move the global PersistentParserState from the CompilerInstance to the source file that code completion is operating on, only hooking up the state when it's needed. This will help make it easier to requestify source file parsing.
1 parent 0d5a5e1 commit d77cae6

File tree

14 files changed

+144
-89
lines changed

14 files changed

+144
-89
lines changed

include/swift/AST/SourceFile.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
namespace swift {
2020

21+
class PersistentParserState;
22+
2123
/// A file containing Swift source code.
2224
///
2325
/// This is a .swift or .sil file (or a virtual file, such as the contents of
@@ -154,6 +156,16 @@ class SourceFile final : public FileUnit {
154156
/// mechanism which is not SourceFile-dependent.)
155157
SeparatelyImportedOverlayMap separatelyImportedOverlays;
156158

159+
/// A pointer to PersistentParserState with a function reference to its
160+
/// deleter to handle the fact that it's forward declared.
161+
using ParserStatePtr =
162+
std::unique_ptr<PersistentParserState, void (*)(PersistentParserState *)>;
163+
164+
/// Stores delayed parser state that code completion needs to be able to
165+
/// resume parsing at the code completion token in the file.
166+
ParserStatePtr DelayedParserState =
167+
ParserStatePtr(/*ptr*/ nullptr, /*deleter*/ nullptr);
168+
157169
friend ASTContext;
158170
friend Impl;
159171

@@ -405,6 +417,20 @@ class SourceFile final : public FileUnit {
405417
/// Retrieve the scope that describes this source file.
406418
ASTScope &getScope();
407419

420+
/// Retrieves the previously set delayed parser state, asserting that it
421+
/// exists.
422+
PersistentParserState *getDelayedParserState() {
423+
auto *state = DelayedParserState.get();
424+
assert(state && "Didn't set any delayed parser state!");
425+
return state;
426+
}
427+
428+
/// Record delayed parser state for the source file. This is needed for code
429+
/// completion's second pass.
430+
void setDelayedParserState(ParserStatePtr &&state) {
431+
DelayedParserState = std::move(state);
432+
}
433+
408434
SWIFT_DEBUG_DUMP;
409435
void dump(raw_ostream &os) const;
410436

include/swift/Frontend/Frontend.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -400,8 +400,6 @@ class CompilerInstance {
400400
std::unique_ptr<Lowering::TypeConverter> TheSILTypes;
401401
std::unique_ptr<SILModule> TheSILModule;
402402

403-
std::unique_ptr<PersistentParserState> PersistentState;
404-
405403
/// Null if no tracker.
406404
std::unique_ptr<DependencyTracker> DepTracker;
407405
/// If there is no stats output directory by the time the
@@ -431,6 +429,9 @@ class CompilerInstance {
431429
/// buffer will also have its buffer ID in PrimaryBufferIDs.
432430
std::vector<SourceFile *> PrimarySourceFiles;
433431

432+
/// The file that has been registered for code completion.
433+
NullablePtr<SourceFile> CodeCompletionFile;
434+
434435
/// Return whether there is an entry in PrimaryInputs for buffer \p BufID.
435436
bool isPrimaryInput(unsigned BufID) const {
436437
return PrimaryBufferIDs.count(BufID) != 0;
@@ -550,12 +551,13 @@ class CompilerInstance {
550551
return Invocation;
551552
}
552553

553-
bool hasPersistentParserState() const {
554-
return bool(PersistentState);
555-
}
554+
/// If a code completion buffer has been set, returns the corresponding source
555+
/// file.
556+
NullablePtr<SourceFile> getCodeCompletionFile() { return CodeCompletionFile; }
556557

557-
PersistentParserState &getPersistentParserState() {
558-
return *PersistentState.get();
558+
/// Set a new file that we're performing code completion on.
559+
void setCodeCompletionFile(SourceFile *file) {
560+
CodeCompletionFile = file;
559561
}
560562

561563
private:

include/swift/Parse/PersistentParserState.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,17 @@ class PersistentParserState {
7979
void restoreCodeCompletionDelayedDeclState(
8080
const CodeCompletionDelayedDeclState &other);
8181

82-
bool hasCodeCompletionDelayedDeclState() {
82+
bool hasCodeCompletionDelayedDeclState() const {
8383
return CodeCompletionDelayedDeclStat.get() != nullptr;
8484
}
8585

8686
CodeCompletionDelayedDeclState &getCodeCompletionDelayedDeclState() {
8787
return *CodeCompletionDelayedDeclStat.get();
8888
}
89+
const CodeCompletionDelayedDeclState &
90+
getCodeCompletionDelayedDeclState() const {
91+
return *CodeCompletionDelayedDeclStat.get();
92+
}
8993

9094
std::unique_ptr<CodeCompletionDelayedDeclState>
9195
takeCodeCompletionDelayedDeclState() {

include/swift/Subsystems.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ namespace swift {
5555
class ModuleDecl;
5656
typedef void *OpaqueSyntaxNode;
5757
class Parser;
58-
class PersistentParserState;
5958
class SerializationOptions;
6059
class SILOptions;
6160
class SILModule;
@@ -110,21 +109,17 @@ namespace swift {
110109
///
111110
/// \param BufferID The buffer to parse from.
112111
///
113-
/// \param PersistentState If non-null the same PersistentState object can be
114-
/// used to save parser state for code completion.
115-
///
116112
/// \param DelayBodyParsing Whether parsing of type and function bodies can be
117113
/// delayed.
118114
void parseIntoSourceFile(SourceFile &SF, unsigned BufferID,
119-
PersistentParserState *PersistentState = nullptr,
120115
bool DelayBodyParsing = true,
121116
bool EvaluateConditionals = true);
122117

123118
/// Parse a source file's SIL declarations into a given SIL module.
124119
void parseSourceFileSIL(SourceFile &SF, SILParserState *sil);
125120

126121
/// Finish the code completion.
127-
void performCodeCompletionSecondPass(PersistentParserState &PersistentState,
122+
void performCodeCompletionSecondPass(SourceFile &SF,
128123
CodeCompletionCallbacksFactory &Factory);
129124

130125
/// Lex and return a vector of tokens for the given buffer.

lib/Frontend/Frontend.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -906,8 +906,6 @@ void CompilerInstance::parseAndCheckTypesUpTo(
906906
const ImplicitImports &implicitImports, SourceFile::ASTStage_t limitStage) {
907907
FrontendStatsTracer tracer(getStatsReporter(), "parse-and-check-types");
908908

909-
PersistentState = std::make_unique<PersistentParserState>();
910-
911909
bool hadLoadError = parsePartialModulesAndLibraryFiles(implicitImports);
912910
if (Invocation.isCodeCompletion()) {
913911
// When we are doing code completion, make sure to emit at least one
@@ -978,8 +976,7 @@ void CompilerInstance::parseLibraryFile(
978976
auto DidSuppressWarnings = Diags.getSuppressWarnings();
979977
Diags.setSuppressWarnings(DidSuppressWarnings || !IsPrimary);
980978

981-
parseIntoSourceFile(*NextInput, BufferID, PersistentState.get(),
982-
/*DelayedBodyParsing=*/!IsPrimary);
979+
parseIntoSourceFile(*NextInput, BufferID, /*DelayedBodyParsing=*/!IsPrimary);
983980

984981
Diags.setSuppressWarnings(DidSuppressWarnings);
985982

@@ -1026,7 +1023,7 @@ void CompilerInstance::parseAndTypeCheckMainFileUpTo(
10261023
Diags.setSuppressWarnings(DidSuppressWarnings || !mainIsPrimary);
10271024

10281025
// Parse the Swift decls into the source file.
1029-
parseIntoSourceFile(MainFile, MainBufferID, PersistentState.get(),
1026+
parseIntoSourceFile(MainFile, MainBufferID,
10301027
/*delayBodyParsing*/ !mainIsPrimary);
10311028

10321029
// For a primary, also perform type checking if needed. Otherwise, just do
@@ -1096,6 +1093,11 @@ SourceFile *CompilerInstance::createSourceFileForMainModule(
10961093
recordPrimarySourceFile(inputFile);
10971094
}
10981095

1096+
if (bufferID == SourceMgr.getCodeCompletionBufferID()) {
1097+
assert(!CodeCompletionFile && "Multiple code completion files?");
1098+
CodeCompletionFile = inputFile;
1099+
}
1100+
10991101
return inputFile;
11001102
}
11011103

@@ -1121,8 +1123,6 @@ void CompilerInstance::performParseOnly(bool EvaluateConditionals,
11211123
MainBufferID);
11221124
}
11231125

1124-
PersistentState = std::make_unique<PersistentParserState>();
1125-
11261126
auto shouldDelayBodies = [&](unsigned bufferID) -> bool {
11271127
if (!CanDelayBodies)
11281128
return false;
@@ -1140,8 +1140,8 @@ void CompilerInstance::performParseOnly(bool EvaluateConditionals,
11401140
SourceFileKind::Library, SourceFile::ImplicitModuleImportKind::None,
11411141
BufferID);
11421142

1143-
parseIntoSourceFile(*NextInput, BufferID, PersistentState.get(),
1144-
shouldDelayBodies(BufferID), EvaluateConditionals);
1143+
parseIntoSourceFile(*NextInput, BufferID, shouldDelayBodies(BufferID),
1144+
EvaluateConditionals);
11451145
}
11461146

11471147
// Now parse the main file.
@@ -1151,16 +1151,15 @@ void CompilerInstance::performParseOnly(bool EvaluateConditionals,
11511151
MainFile.SyntaxParsingCache = Invocation.getMainFileSyntaxParsingCache();
11521152
assert(MainBufferID == MainFile.getBufferID());
11531153

1154-
parseIntoSourceFile(MainFile, MainBufferID, PersistentState.get(),
1155-
shouldDelayBodies(MainBufferID), EvaluateConditionals);
1154+
parseIntoSourceFile(MainFile, MainBufferID, shouldDelayBodies(MainBufferID),
1155+
EvaluateConditionals);
11561156
}
11571157

11581158
assert(Context->LoadedModules.size() == 1 &&
11591159
"Loaded a module during parse-only");
11601160
}
11611161

11621162
void CompilerInstance::freeASTContext() {
1163-
PersistentState.reset();
11641163
TheSILTypes.reset();
11651164
Context.reset();
11661165
MainModule = nullptr;

lib/IDE/CompletionInstance.cpp

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -176,21 +176,17 @@ bool CompletionInstance::performCachedOperaitonIfPossible(
176176
return false;
177177

178178
auto &CI = *CachedCI;
179+
auto *oldSF = CI.getCodeCompletionFile().get();
179180

180-
if (!CI.hasPersistentParserState())
181-
return false;
182-
auto &oldState = CI.getPersistentParserState();
183-
if (!oldState.hasCodeCompletionDelayedDeclState())
184-
return false;
181+
auto *oldState = oldSF->getDelayedParserState();
182+
assert(oldState->hasCodeCompletionDelayedDeclState());
183+
auto &oldInfo = oldState->getCodeCompletionDelayedDeclState();
185184

186185
auto &SM = CI.getSourceMgr();
187186
if (SM.getIdentifierForBuffer(SM.getCodeCompletionBufferID()) !=
188187
completionBuffer->getBufferIdentifier())
189188
return false;
190189

191-
auto &oldInfo = oldState.getCodeCompletionDelayedDeclState();
192-
auto *oldSF = oldInfo.ParentContext->getParentSourceFile();
193-
194190
// Parse the new buffer into temporary SourceFile.
195191
SourceManager tmpSM;
196192
auto tmpBufferID = tmpSM.addMemBufferCopy(completionBuffer);
@@ -207,19 +203,20 @@ bool CompletionInstance::performCachedOperaitonIfPossible(
207203
registerTypeCheckerRequestFunctions(tmpCtx->evaluator);
208204
registerSILGenRequestFunctions(tmpCtx->evaluator);
209205
ModuleDecl *tmpM = ModuleDecl::create(Identifier(), *tmpCtx);
210-
PersistentParserState newState;
211206
SourceFile *tmpSF =
212207
new (*tmpCtx) SourceFile(*tmpM, oldSF->Kind, tmpBufferID,
213208
SourceFile::ImplicitModuleImportKind::None);
214209
tmpSF->enableInterfaceHash();
215210
// Ensure all non-function-body tokens are hashed into the interface hash
216211
tmpCtx->LangOpts.EnableTypeFingerprints = false;
217-
parseIntoSourceFile(*tmpSF, tmpBufferID, &newState);
212+
parseIntoSourceFile(*tmpSF, tmpBufferID);
213+
218214
// Couldn't find any completion token?
219-
if (!newState.hasCodeCompletionDelayedDeclState())
215+
auto *newState = tmpSF->getDelayedParserState();
216+
if (!newState->hasCodeCompletionDelayedDeclState())
220217
return false;
221218

222-
auto &newInfo = newState.getCodeCompletionDelayedDeclState();
219+
auto &newInfo = newState->getCodeCompletionDelayedDeclState();
223220
unsigned newBufferID;
224221

225222
switch (newInfo.Kind) {
@@ -273,7 +270,7 @@ bool CompletionInstance::performCachedOperaitonIfPossible(
273270

274271
// Construct dummy scopes. We don't need to restore the original scope
275272
// because they are probably not 'isResolvable()' anyway.
276-
auto &SI = oldState.getScopeInfo();
273+
auto &SI = oldState->getScopeInfo();
277274
assert(SI.getCurrentScope() == nullptr);
278275
Scope Top(SI, ScopeKind::TopLevel);
279276
Scope Body(SI, ScopeKind::FunctionBody);
@@ -282,7 +279,7 @@ bool CompletionInstance::performCachedOperaitonIfPossible(
282279
oldInfo.StartOffset = newInfo.StartOffset;
283280
oldInfo.EndOffset = newInfo.EndOffset;
284281
oldInfo.PrevOffset = newInfo.PrevOffset;
285-
oldState.restoreCodeCompletionDelayedDeclState(oldInfo);
282+
oldState->restoreCodeCompletionDelayedDeclState(oldInfo);
286283

287284
auto *AFD = cast<AbstractFunctionDecl>(DC);
288285
if (AFD->isBodySkipped())
@@ -324,14 +321,22 @@ bool CompletionInstance::performCachedOperaitonIfPossible(
324321
CompilerInstance::addAdditionalInitialImportsTo(newSF, implicitImport);
325322
newSF->enableInterfaceHash();
326323

324+
// Tell the compiler instance we've replaced the code completion file.
325+
CI.setCodeCompletionFile(newSF);
326+
327327
// Re-parse the whole file. Still re-use imported modules.
328-
(void)oldState.takeCodeCompletionDelayedDeclState();
329-
parseIntoSourceFile(*newSF, newBufferID, &oldState);
328+
parseIntoSourceFile(*newSF, newBufferID);
330329
performNameBinding(*newSF);
331330
bindExtensions(*newSF);
332331

333-
assert(oldState.hasCodeCompletionDelayedDeclState() &&
334-
oldState.getCodeCompletionDelayedDeclState().Kind == newInfo.Kind);
332+
#ifndef NDEBUG
333+
const auto *reparsedState = newSF->getDelayedParserState();
334+
assert(reparsedState->hasCodeCompletionDelayedDeclState() &&
335+
"Didn't find completion token?");
336+
337+
auto &reparsedInfo = reparsedState->getCodeCompletionDelayedDeclState();
338+
assert(reparsedInfo.Kind == newInfo.Kind);
339+
#endif
335340
break;
336341
}
337342
}
@@ -360,27 +365,42 @@ bool CompletionInstance::performNewOperation(
360365
llvm::function_ref<void(CompilerInstance &)> Callback) {
361366

362367
auto TheInstance = std::make_unique<CompilerInstance>();
363-
auto &CI = *TheInstance;
364-
if (DiagC)
365-
CI.addDiagnosticConsumer(DiagC);
368+
{
369+
auto &CI = *TheInstance;
370+
if (DiagC)
371+
CI.addDiagnosticConsumer(DiagC);
366372

367-
if (FileSystem != llvm::vfs::getRealFileSystem())
368-
CI.getSourceMgr().setFileSystem(FileSystem);
373+
SWIFT_DEFER {
374+
if (DiagC)
375+
CI.removeDiagnosticConsumer(DiagC);
376+
};
369377

370-
Invocation.setCodeCompletionPoint(completionBuffer, Offset);
378+
if (FileSystem != llvm::vfs::getRealFileSystem())
379+
CI.getSourceMgr().setFileSystem(FileSystem);
371380

372-
if (CI.setup(Invocation)) {
373-
Error = "failed to setup compiler instance";
374-
return false;
375-
}
376-
registerIDERequestFunctions(CI.getASTContext().evaluator);
381+
Invocation.setCodeCompletionPoint(completionBuffer, Offset);
377382

378-
CI.performParseAndResolveImportsOnly();
379-
if (CI.hasPersistentParserState())
380-
Callback(CI);
383+
if (CI.setup(Invocation)) {
384+
Error = "failed to setup compiler instance";
385+
return false;
386+
}
387+
registerIDERequestFunctions(CI.getASTContext().evaluator);
381388

382-
if (DiagC)
383-
CI.removeDiagnosticConsumer(DiagC);
389+
CI.performParseAndResolveImportsOnly();
390+
391+
// If we didn't create a source file for completion, bail. This can happen
392+
// if for example we fail to load the stdlib.
393+
auto completionFile = CI.getCodeCompletionFile();
394+
if (!completionFile)
395+
return true;
396+
397+
// If we didn't find a code completion token, bail.
398+
auto *state = completionFile.get()->getDelayedParserState();
399+
if (!state->hasCodeCompletionDelayedDeclState())
400+
return true;
401+
402+
Callback(CI);
403+
}
384404

385405
if (ArgsHash.hasValue()) {
386406
CachedCI = std::move(TheInstance);

lib/IDE/REPLCodeCompletion.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,11 +232,10 @@ doCodeCompletion(SourceFile &SF, StringRef EnteredCode, unsigned *BufferID,
232232
newSF.addImports(importsWithOptions);
233233
}
234234

235-
PersistentParserState PersistentState;
236-
parseIntoSourceFile(newSF, *BufferID, &PersistentState);
235+
parseIntoSourceFile(newSF, *BufferID);
237236
performTypeChecking(newSF);
238237

239-
performCodeCompletionSecondPass(PersistentState, *CompletionCallbacksFactory);
238+
performCodeCompletionSecondPass(newSF, *CompletionCallbacksFactory);
240239

241240
// Reset the error state because it's only relevant to the code that we just
242241
// processed, which now gets thrown away.

0 commit comments

Comments
 (0)