Skip to content

Commit

Permalink
Merge pull request apple#29664 from hamishknight/inout-decls
Browse files Browse the repository at this point in the history
Create a new module and SourceFile for REPL completion
  • Loading branch information
hamishknight authored and Marc Rasi committed Feb 6, 2020
1 parent 605f23b commit 3af8377
Show file tree
Hide file tree
Showing 15 changed files with 69 additions and 69 deletions.
6 changes: 2 additions & 4 deletions include/swift/AST/TypeCheckRequests.h
Expand Up @@ -1959,17 +1959,15 @@ class DynamicallyReplacedDeclRequest

class TypeCheckSourceFileRequest :
public SimpleRequest<TypeCheckSourceFileRequest,
bool (SourceFile *, unsigned),
CacheKind::SeparatelyCached> {
bool (SourceFile *), CacheKind::SeparatelyCached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
llvm::Expected<bool> evaluate(Evaluator &evaluator,
SourceFile *SF, unsigned StartElem) const;
llvm::Expected<bool> evaluate(Evaluator &evaluator, SourceFile *SF) const;

public:
// Separate caching.
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/TypeCheckerTypeIDZone.def
Expand Up @@ -211,7 +211,7 @@ SWIFT_REQUEST(TypeChecker, HasDefaultInitRequest,
SWIFT_REQUEST(TypeChecker, SynthesizeDefaultInitRequest,
ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, TypeCheckSourceFileRequest,
bool(SouceFile *, unsigned), SeparatelyCached, NoLocationInfo)
bool(SouceFile *), SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, TypeWitnessRequest,
TypeWitnessAndDecl(NormalProtocolConformance *,
AssociatedTypeDecl *),
Expand Down
2 changes: 0 additions & 2 deletions include/swift/Frontend/Frontend.h
Expand Up @@ -653,8 +653,6 @@ class CompilerInstance {
};

private:
void createREPLFile(const ImplicitImports &implicitImports);

void addMainFileToModule(const ImplicitImports &implicitImports);

void performSemaUpTo(SourceFile::ASTStage_t LimitStage);
Expand Down
10 changes: 2 additions & 8 deletions include/swift/Subsystems.h
Expand Up @@ -137,10 +137,7 @@ namespace swift {

/// Once parsing is complete, this walks the AST to resolve imports, record
/// operators, and do other top-level validation.
///
/// \param StartElem Where to start for incremental name binding in the main
/// source file.
void performNameBinding(SourceFile &SF, unsigned StartElem = 0);
void performNameBinding(SourceFile &SF);

/// Once type-checking is complete, this instruments code with calls to an
/// intrinsic that record the expected values of local variables so they can
Expand Down Expand Up @@ -171,10 +168,7 @@ namespace swift {

/// Once parsing and name-binding are complete, this walks the AST to resolve
/// types and diagnose problems therein.
///
/// \param StartElem Where to start for incremental type-checking in the main
/// source file.
void performTypeChecking(SourceFile &SF, unsigned StartElem = 0);
void performTypeChecking(SourceFile &SF);

/// Now that we have type-checked an entire module, perform any type
/// checking that requires the full module, e.g., Objective-C method
Expand Down
16 changes: 9 additions & 7 deletions lib/Frontend/Frontend.cpp
Expand Up @@ -727,7 +727,15 @@ void CompilerInstance::performSemaUpTo(SourceFile::ASTStage_t LimitStage) {
const ImplicitImports implicitImports(*this);

if (Invocation.getInputKind() == InputFileKind::SwiftREPL) {
createREPLFile(implicitImports);
// Create the initial empty REPL file. This only exists to feed in the
// implicit imports such as the standard library.
auto *replFile = createSourceFileForMainModule(
SourceFileKind::REPL, implicitImports.kind, /*BufferID*/ None);
addAdditionalInitialImportsTo(replFile, implicitImports);

// Given this file is empty, we can go ahead and just mark it as having been
// type checked.
replFile->ASTStage = SourceFile::TypeChecked;
return;
}

Expand Down Expand Up @@ -824,12 +832,6 @@ void CompilerInstance::getImplicitlyImportedModules(
}
}

void CompilerInstance::createREPLFile(const ImplicitImports &implicitImports) {
auto *SingleInputFile = createSourceFileForMainModule(
Invocation.getSourceFileKind(), implicitImports.kind, None);
addAdditionalInitialImportsTo(SingleInputFile, implicitImports);
}

void CompilerInstance::addMainFileToModule(
const ImplicitImports &implicitImports) {
auto *MainFile = createSourceFileForMainModule(
Expand Down
37 changes: 29 additions & 8 deletions lib/IDE/REPLCodeCompletion.cpp
Expand Up @@ -204,19 +204,40 @@ doCodeCompletion(SourceFile &SF, StringRef EnteredCode, unsigned *BufferID,

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

// Parse, typecheck and temporarily insert the incomplete code into the AST.
const unsigned OriginalDeclCount = SF.getTopLevelDecls().size();
// Create a new module and file for the code completion buffer, similar to how
// we handle new lines of REPL input.
auto *newModule =
ModuleDecl::create(Ctx.getIdentifier("REPL_Code_Completion"), Ctx);
auto &newSF =
*new (Ctx) SourceFile(*newModule, SourceFileKind::REPL, *BufferID,
SourceFile::ImplicitModuleImportKind::None);
newModule->addFile(newSF);

// Import the last module.
auto *lastModule = SF.getParentModule();
ModuleDecl::ImportedModule importOfLastModule{/*AccessPath*/ {}, lastModule};
newSF.addImports(SourceFile::ImportedModuleDesc(importOfLastModule,
SourceFile::ImportOptions()));

// Carry over the private imports from the last module.
SmallVector<ModuleDecl::ImportedModule, 8> imports;
lastModule->getImportedModules(imports,
ModuleDecl::ImportFilterKind::Private);
if (!imports.empty()) {
SmallVector<SourceFile::ImportedModuleDesc, 8> importsWithOptions;
for (auto &import : imports) {
importsWithOptions.emplace_back(
SourceFile::ImportedModuleDesc(import, SourceFile::ImportOptions()));
}
newSF.addImports(importsWithOptions);
}

PersistentParserState PersistentState;
parseIntoSourceFile(SF, *BufferID, &PersistentState);
performTypeChecking(SF, OriginalDeclCount);
parseIntoSourceFile(newSF, *BufferID, &PersistentState);
performTypeChecking(newSF);

performCodeCompletionSecondPass(PersistentState, *CompletionCallbacksFactory);

// Now we are done with code completion. Remove the declarations we
// temporarily inserted.
SF.truncateTopLevelDecls(OriginalDeclCount);

// Reset the error state because it's only relevant to the code that we just
// processed, which now gets thrown away.
Ctx.Diags.resetHadAnyError();
Expand Down
4 changes: 0 additions & 4 deletions lib/Immediate/REPL.cpp
Expand Up @@ -997,10 +997,6 @@ class REPLEnvironment {
IRGenOpts.DebugInfoLevel = IRGenDebugInfoLevel::None;
IRGenOpts.DebugInfoFormat = IRGenDebugInfoFormat::None;

// The very first module is a dummy.
CI.getMainModule()->getMainSourceFile(SourceFileKind::REPL).ASTStage =
SourceFile::TypeChecked;

if (!ParseStdlib) {
// Force standard library to be loaded immediately. This forces any
// errors to appear upfront, and helps eliminate some nasty lag after the
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/NameBinding.cpp
Expand Up @@ -397,7 +397,7 @@ static void insertPrecedenceGroupDecl(NameBinder &binder, SourceFile &SF,
/// UnresolvedDeclRefExpr nodes for unresolved value names, and we may have
/// unresolved type names as well. This handles import directives and forward
/// references.
void swift::performNameBinding(SourceFile &SF, unsigned StartElem) {
void swift::performNameBinding(SourceFile &SF) {
FrontendStatsTracer tracer(SF.getASTContext().Stats, "Name binding");

// Make sure we skip adding the standard library imports if the
Expand All @@ -417,7 +417,7 @@ void swift::performNameBinding(SourceFile &SF, unsigned StartElem) {

// Do a prepass over the declarations to find and load the imported modules
// and map operator decls.
for (auto D : SF.getTopLevelDecls().slice(StartElem)) {
for (auto D : SF.getTopLevelDecls()) {
if (auto *ID = dyn_cast<ImportDecl>(D)) {
Binder.addImport(ImportedModules, ID);
} else if (auto *OD = dyn_cast<PrefixOperatorDecl>(D)) {
Expand Down
12 changes: 3 additions & 9 deletions lib/Sema/TypeCheckAvailability.cpp
Expand Up @@ -614,14 +614,8 @@ class TypeRefinementContextBuilder : private ASTWalker {

} // end anonymous namespace

void TypeChecker::buildTypeRefinementContextHierarchy(SourceFile &SF,
unsigned StartElem) {
void TypeChecker::buildTypeRefinementContextHierarchy(SourceFile &SF) {
TypeRefinementContext *RootTRC = SF.getTypeRefinementContext();

// If we are not starting at the beginning of the source file, we had better
// already have a root type refinement context.
assert(StartElem == 0 || RootTRC);

ASTContext &Context = SF.getASTContext();

if (!RootTRC) {
Expand All @@ -636,7 +630,7 @@ void TypeChecker::buildTypeRefinementContextHierarchy(SourceFile &SF,
// Build refinement contexts, if necessary, for all declarations starting
// with StartElem.
TypeRefinementContextBuilder Builder(RootTRC, Context);
for (auto D : SF.getTopLevelDecls().slice(StartElem)) {
for (auto D : SF.getTopLevelDecls()) {
Builder.build(D);
}
}
Expand All @@ -645,7 +639,7 @@ TypeRefinementContext *
TypeChecker::getOrBuildTypeRefinementContext(SourceFile *SF) {
TypeRefinementContext *TRC = SF->getTypeRefinementContext();
if (!TRC) {
buildTypeRefinementContextHierarchy(*SF, 0);
buildTypeRefinementContextHierarchy(*SF);
TRC = SF->getTypeRefinementContext();
}

Expand Down
8 changes: 4 additions & 4 deletions lib/Sema/TypeCheckREPL.cpp
Expand Up @@ -462,17 +462,17 @@ Identifier REPLChecker::getNextResponseVariableName(DeclContext *DC) {
/// processREPLTopLevel - This is called after we've parsed and typechecked some
/// new decls at the top level. We inject code to print out expressions and
/// pattern bindings the are evaluated.
void TypeChecker::processREPLTopLevel(SourceFile &SF, unsigned FirstDecl) {
void TypeChecker::processREPLTopLevel(SourceFile &SF) {
// Walk over all decls in the file to find the next available closure
// discriminator.
DiscriminatorFinder DF;
for (Decl *D : SF.getTopLevelDecls())
D->walk(DF);

// Move new declarations out.
std::vector<Decl *> NewDecls(SF.getTopLevelDecls().begin()+FirstDecl,
// Move the new declarations out of the source file.
std::vector<Decl *> NewDecls(SF.getTopLevelDecls().begin(),
SF.getTopLevelDecls().end());
SF.truncateTopLevelDecls(FirstDecl);
SF.truncateTopLevelDecls(0);

REPLChecker RC(SF, DF);

Expand Down
16 changes: 7 additions & 9 deletions lib/Sema/TypeChecker.cpp
Expand Up @@ -331,15 +331,13 @@ static void typeCheckFunctionsAndExternalDecls(SourceFile &SF, TypeChecker &TC)
TC.definedFunctions.clear();
}

void swift::performTypeChecking(SourceFile &SF, unsigned StartElem) {
void swift::performTypeChecking(SourceFile &SF) {
return (void)evaluateOrDefault(SF.getASTContext().evaluator,
TypeCheckSourceFileRequest{&SF, StartElem},
false);
TypeCheckSourceFileRequest{&SF}, false);
}

llvm::Expected<bool>
TypeCheckSourceFileRequest::evaluate(Evaluator &eval,
SourceFile *SF, unsigned StartElem) const {
TypeCheckSourceFileRequest::evaluate(Evaluator &eval, SourceFile *SF) const {
assert(SF && "Source file cannot be null!");
assert(SF->ASTStage != SourceFile::TypeChecked &&
"Should not be re-typechecking this file!");
Expand All @@ -360,7 +358,7 @@ TypeCheckSourceFileRequest::evaluate(Evaluator &eval,

// Make sure that name binding has been completed before doing any type
// checking.
performNameBinding(*SF, StartElem);
performNameBinding(*SF);

// Could build scope maps here because the AST is stable now.

Expand All @@ -377,7 +375,7 @@ TypeCheckSourceFileRequest::evaluate(Evaluator &eval,
if (!Ctx.LangOpts.DisableAvailabilityChecking) {
// Build the type refinement hierarchy for the primary
// file before type checking.
TypeChecker::buildTypeRefinementContextHierarchy(*SF, StartElem);
TypeChecker::buildTypeRefinementContextHierarchy(*SF);
}

// Resolve extensions. This has to occur first during type checking,
Expand All @@ -386,7 +384,7 @@ TypeCheckSourceFileRequest::evaluate(Evaluator &eval,
::bindExtensions(*SF);

// Type check the top-level elements of the source file.
for (auto D : SF->getTopLevelDecls().slice(StartElem)) {
for (auto D : SF->getTopLevelDecls()) {
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
// Immediately perform global name-binding etc.
TypeChecker::typeCheckTopLevelCodeDecl(TLCD);
Expand All @@ -399,7 +397,7 @@ TypeCheckSourceFileRequest::evaluate(Evaluator &eval,
// If we're in REPL mode, inject temporary result variables and other stuff
// that the REPL needs to synthesize.
if (SF->Kind == SourceFileKind::REPL && !Ctx.hadError())
TypeChecker::processREPLTopLevel(*SF, StartElem);
TypeChecker::processREPLTopLevel(*SF);

typeCheckFunctionsAndExternalDecls(*SF, TC);
}
Expand Down
8 changes: 2 additions & 6 deletions lib/Sema/TypeChecker.h
Expand Up @@ -718,7 +718,7 @@ class TypeChecker final {

static void typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD);

static void processREPLTopLevel(SourceFile &SF, unsigned StartElem);
static void processREPLTopLevel(SourceFile &SF);

static void typeCheckDecl(Decl *D);

Expand Down Expand Up @@ -1491,11 +1491,7 @@ class TypeChecker final {
const TypeRefinementContext **MostRefined=nullptr);

/// Walk the AST to build the hierarchy of TypeRefinementContexts
///
/// \param StartElem Where to start for incremental building of refinement
/// contexts
static void buildTypeRefinementContextHierarchy(SourceFile &SF,
unsigned StartElem);
static void buildTypeRefinementContextHierarchy(SourceFile &SF);

/// Build the hierarchy of TypeRefinementContexts for the entire
/// source file, if it has not already been built. Returns the root
Expand Down

This file was deleted.

@@ -0,0 +1,3 @@
// RUN: %target-swift-ide-test -repl-code-completion -source-filename %s

struct Bar:
@@ -0,0 +1,5 @@
// RUN: %target-swift-ide-test -repl-code-completion -source-filename %s

struct Foo<T> {}

extension Foo whe

0 comments on commit 3af8377

Please sign in to comment.