Skip to content

Commit 5ed2847

Browse files
committed
Create a new module and SourceFile for REPL completion
Rather than attempting to temporarily insert decls into the last source file, just create a new module and source file and carry across the imports from the last module. This matches how the REPL deals with new lines of input.
1 parent e594622 commit 5ed2847

File tree

4 files changed

+37
-13
lines changed

4 files changed

+37
-13
lines changed

lib/IDE/REPLCodeCompletion.cpp

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -204,19 +204,40 @@ doCodeCompletion(SourceFile &SF, StringRef EnteredCode, unsigned *BufferID,
204204

205205
Ctx.SourceMgr.setCodeCompletionPoint(*BufferID, CodeCompletionOffset);
206206

207-
// Parse, typecheck and temporarily insert the incomplete code into the AST.
208-
const unsigned OriginalDeclCount = SF.getTopLevelDecls().size();
207+
// Create a new module and file for the code completion buffer, similar to how
208+
// we handle new lines of REPL input.
209+
auto *newModule =
210+
ModuleDecl::create(Ctx.getIdentifier("REPL_Code_Completion"), Ctx);
211+
auto &newSF =
212+
*new (Ctx) SourceFile(*newModule, SourceFileKind::REPL, *BufferID,
213+
SourceFile::ImplicitModuleImportKind::None);
214+
newModule->addFile(newSF);
215+
216+
// Import the last module.
217+
auto *lastModule = SF.getParentModule();
218+
ModuleDecl::ImportedModule importOfLastModule{/*AccessPath*/ {}, lastModule};
219+
newSF.addImports(SourceFile::ImportedModuleDesc(importOfLastModule,
220+
SourceFile::ImportOptions()));
221+
222+
// Carry over the private imports from the last module.
223+
SmallVector<ModuleDecl::ImportedModule, 8> imports;
224+
lastModule->getImportedModules(imports,
225+
ModuleDecl::ImportFilterKind::Private);
226+
if (!imports.empty()) {
227+
SmallVector<SourceFile::ImportedModuleDesc, 8> importsWithOptions;
228+
for (auto &import : imports) {
229+
importsWithOptions.emplace_back(
230+
SourceFile::ImportedModuleDesc(import, SourceFile::ImportOptions()));
231+
}
232+
newSF.addImports(importsWithOptions);
233+
}
209234

210235
PersistentParserState PersistentState;
211-
parseIntoSourceFile(SF, *BufferID, &PersistentState);
212-
performTypeChecking(SF, OriginalDeclCount);
236+
parseIntoSourceFile(newSF, *BufferID, &PersistentState);
237+
performTypeChecking(newSF);
213238

214239
performCodeCompletionSecondPass(PersistentState, *CompletionCallbacksFactory);
215240

216-
// Now we are done with code completion. Remove the declarations we
217-
// temporarily inserted.
218-
SF.truncateTopLevelDecls(OriginalDeclCount);
219-
220241
// Reset the error state because it's only relevant to the code that we just
221242
// processed, which now gets thrown away.
222243
Ctx.Diags.resetHadAnyError();

validation-test/IDE/crashers_2/complete_repl_decl_conformance.swift

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// RUN: %target-swift-ide-test -repl-code-completion -source-filename %s
2+
3+
struct Bar:
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// RUN: %target-swift-ide-test -repl-code-completion -source-filename %s
2+
3+
struct Foo<T> {}
4+
5+
extension Foo whe

0 commit comments

Comments
 (0)