[CodeCompletion] Avoid typechecking all toplevel decls in the current file

- Use `performParseAndResolveImportsOnly()` to invoke the frontend
- Do `bindExtensions()` in `ide::typeCheckContextUntil()`
- Typecheck preceding `TopLevelCodeDecl`s only if the compleiton is in
  a `TopLevelCodeDecl`
- Other related tweaks

rdar://problem/56636747
This commit is contained in:
Rintaro Ishizaki
2019-10-30 17:13:16 -07:00
parent 9203080c0e
commit 2564a6e494
13 changed files with 109 additions and 39 deletions

View File

@@ -22,6 +22,7 @@
#include "swift/AST/Module.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/Stmt.h"
#include "swift/AST/Type.h"
#include "swift/AST/Types.h"
@@ -61,10 +62,9 @@ void typeCheckContextImpl(DeclContext *DC, SourceLoc Loc) {
if (auto *patternInit = dyn_cast<PatternBindingInitializer>(DC)) {
if (auto *PBD = patternInit->getBinding()) {
auto i = patternInit->getBindingIndex();
PBD->getPattern(i)->forEachVariable(
[](VarDecl *VD) { (void)VD->getInterfaceType(); });
if (PBD->getInit(i)) {
PBD->getPattern(i)->forEachVariable([](VarDecl *VD) {
(void) VD->getInterfaceType();
});
if (!PBD->isInitializerChecked(i))
typeCheckPatternBinding(PBD, i);
}
@@ -91,15 +91,35 @@ void typeCheckContextImpl(DeclContext *DC, SourceLoc Loc) {
} // anonymous namespace
void swift::ide::typeCheckContextUntil(DeclContext *DC, SourceLoc Loc) {
// The only time we have to explicitly check a TopLevelCodeDecl
// is when we're directly inside of one. In this case,
// performTypeChecking() did not type check it for us.
// Lookup the swift module. This ensures that we record all known
// protocols in the AST.
(void) DC->getASTContext().getStdlibModule();
bindExtensions(*DC->getParentSourceFile());
while (isa<AbstractClosureExpr>(DC))
DC = DC->getParent();
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(DC))
typeCheckTopLevelCodeDecl(TLCD);
else
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(DC)) {
// Typecheck all 'TopLevelCodeDecl's up to the target one.
// In theory, this is not needed, but it fails to resolve the type of
// 'guard'ed variable. e.g.
//
// guard value = something() else { fatalError() }
// <complete>
// Here, 'value' is '<error type>' unless we explicitly typecheck the
// 'guard' statement.
SourceFile *SF = DC->getParentSourceFile();
for (auto *D : SF->Decls) {
if (auto Code = dyn_cast<TopLevelCodeDecl>(D)) {
typeCheckTopLevelCodeDecl(Code);
if (Code == TLCD)
break;
}
}
} else {
typeCheckContextImpl(DC, Loc);
}
}
//===----------------------------------------------------------------------===//