Skip to content

Commit 65b8cf7

Browse files
authored
Merge pull request swiftlang#32086 from rintaro/ide-completion-skipbody-rdar58687608
[CodeCompletion] Skip type checking unrelated statements in function body
2 parents 736a848 + 3144119 commit 65b8cf7

17 files changed

+234
-129
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -867,14 +867,13 @@ class LazyStoragePropertyRequest :
867867
bool isCached() const { return true; }
868868
};
869869

870-
/// Request to type check the body of the given function up to the given
871-
/// source location.
870+
/// Request to type check the body of the given function.
872871
///
873872
/// Produces true if an error occurred, false otherwise.
874873
/// FIXME: it would be far better to return the type-checked body.
875-
class TypeCheckFunctionBodyUntilRequest :
876-
public SimpleRequest<TypeCheckFunctionBodyUntilRequest,
877-
bool(AbstractFunctionDecl *, SourceLoc),
874+
class TypeCheckFunctionBodyRequest :
875+
public SimpleRequest<TypeCheckFunctionBodyRequest,
876+
bool(AbstractFunctionDecl *),
878877
RequestFlags::Cached|RequestFlags::DependencySource> {
879878
public:
880879
using SimpleRequest::SimpleRequest;
@@ -883,9 +882,7 @@ class TypeCheckFunctionBodyUntilRequest :
883882
friend SimpleRequest;
884883

885884
// Evaluation.
886-
bool
887-
evaluate(Evaluator &evaluator, AbstractFunctionDecl *func,
888-
SourceLoc endTypeCheckLoc) const;
885+
bool evaluate(Evaluator &evaluator, AbstractFunctionDecl *func) const;
889886

890887
public:
891888
bool isCached() const { return true; }
@@ -896,6 +893,24 @@ class TypeCheckFunctionBodyUntilRequest :
896893
readDependencySource(const evaluator::DependencyRecorder &) const;
897894
};
898895

896+
/// Request to typecheck a function body element at the given source location.
897+
///
898+
/// Produces true if an error occurred, false otherwise.
899+
class TypeCheckFunctionBodyAtLocRequest
900+
: public SimpleRequest<TypeCheckFunctionBodyAtLocRequest,
901+
bool(AbstractFunctionDecl *, SourceLoc),
902+
RequestFlags::Uncached> {
903+
public:
904+
using SimpleRequest::SimpleRequest;
905+
906+
private:
907+
friend SimpleRequest;
908+
909+
// Evaluation.
910+
bool evaluate(Evaluator &evaluator, AbstractFunctionDecl *func,
911+
SourceLoc Loc) const;
912+
};
913+
899914
/// Request to obtain a list of stored properties in a nominal type.
900915
///
901916
/// This will include backing storage for lazy properties and

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,11 @@ SWIFT_REQUEST(TypeChecker, SuperclassTypeRequest,
198198
SWIFT_REQUEST(TypeChecker, SynthesizeAccessorRequest,
199199
AccessorDecl *(AbstractStorageDecl *, AccessorKind),
200200
SeparatelyCached, NoLocationInfo)
201-
SWIFT_REQUEST(TypeChecker, TypeCheckFunctionBodyUntilRequest,
201+
SWIFT_REQUEST(TypeChecker, TypeCheckFunctionBodyRequest,
202+
bool(AbstractFunctionDecl *), Cached, NoLocationInfo)
203+
SWIFT_REQUEST(TypeChecker, TypeCheckFunctionBodyAtLocRequest,
202204
bool(AbstractFunctionDecl *, SourceLoc),
203-
Cached, NoLocationInfo)
205+
Uncached, NoLocationInfo)
204206
SWIFT_REQUEST(TypeChecker, UnderlyingTypeRequest, Type(TypeAliasDecl *),
205207
SeparatelyCached, NoLocationInfo)
206208
SWIFT_REQUEST(TypeChecker, USRGenerationRequest, std::string(const ValueDecl *),

include/swift/Sema/IDETypeChecking.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,9 @@ namespace swift {
132132
/// Typecheck the given expression.
133133
bool typeCheckExpression(DeclContext *DC, Expr *&parsedExpr);
134134

135-
/// Partially typecheck the specified function body.
136-
bool typeCheckAbstractFunctionBodyUntil(AbstractFunctionDecl *AFD,
137-
SourceLoc EndTypeCheckLoc);
135+
/// Type check a function body element which is at \p TagetLoc .
136+
bool typeCheckAbstractFunctionBodyAtLoc(AbstractFunctionDecl *AFD,
137+
SourceLoc TargetLoc);
138138

139139
/// Typecheck top-level code parsed during code completion.
140140
///

lib/AST/TypeCheckRequests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,11 +1455,11 @@ void TypeCheckSourceFileRequest::cacheResult(evaluator::SideEffect) const {
14551455
}
14561456

14571457
//----------------------------------------------------------------------------//
1458-
// TypeCheckFunctionBodyUntilRequest computation.
1458+
// TypeCheckFunctionBodyRequest computation.
14591459
//----------------------------------------------------------------------------//
14601460

14611461
evaluator::DependencySource
1462-
TypeCheckFunctionBodyUntilRequest::readDependencySource(
1462+
TypeCheckFunctionBodyRequest::readDependencySource(
14631463
const evaluator::DependencyRecorder &e) const {
14641464
// We're going under a function body scope, unconditionally flip the scope
14651465
// to private.

lib/IDE/CodeCompletion.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5734,9 +5734,11 @@ void CodeCompletionCallbacksImpl::doneParsing() {
57345734
CurDeclContext = DC;
57355735
}
57365736

5737-
typeCheckContextUntil(
5737+
typeCheckContextAt(
57385738
CurDeclContext,
5739-
CurDeclContext->getASTContext().SourceMgr.getCodeCompletionLoc());
5739+
ParsedExpr
5740+
? ParsedExpr->getLoc()
5741+
: CurDeclContext->getASTContext().SourceMgr.getCodeCompletionLoc());
57405742

57415743
// Add keywords even if type checking fails completely.
57425744
addKeywords(CompletionContext.getResultSink(), MaybeFuncBody);

lib/IDE/ConformingMethodList.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,7 @@ void ConformingMethodListCallbacks::doneParsing() {
6767
if (!ParsedExpr)
6868
return;
6969

70-
typeCheckContextUntil(
71-
CurDeclContext,
72-
CurDeclContext->getASTContext().SourceMgr.getCodeCompletionLoc());
70+
typeCheckContextAt(CurDeclContext, ParsedExpr->getLoc());
7371

7472
Type T = ParsedExpr->getType();
7573

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ using namespace swift;
3838
using namespace ide;
3939

4040
//===----------------------------------------------------------------------===//
41-
// typeCheckContextUntil(DeclContext, SourceLoc)
41+
// typeCheckContextAt(DeclContext, SourceLoc)
4242
//===----------------------------------------------------------------------===//
4343

4444
namespace {
@@ -80,7 +80,7 @@ void typeCheckContextImpl(DeclContext *DC, SourceLoc Loc) {
8080
auto &SM = DC->getASTContext().SourceMgr;
8181
auto bodyRange = AFD->getBodySourceRange();
8282
if (SM.rangeContainsTokenLoc(bodyRange, Loc)) {
83-
swift::typeCheckAbstractFunctionBodyUntil(AFD, Loc);
83+
swift::typeCheckAbstractFunctionBodyAtLoc(AFD, Loc);
8484
} else {
8585
assert(bodyRange.isInvalid() && "The body should not be parsed if the "
8686
"completion happens in the signature");
@@ -100,27 +100,12 @@ void typeCheckContextImpl(DeclContext *DC, SourceLoc Loc) {
100100
}
101101
} // anonymous namespace
102102

103-
void swift::ide::typeCheckContextUntil(DeclContext *DC, SourceLoc Loc) {
103+
void swift::ide::typeCheckContextAt(DeclContext *DC, SourceLoc Loc) {
104104
while (isa<AbstractClosureExpr>(DC))
105105
DC = DC->getParent();
106106

107107
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(DC)) {
108-
// Typecheck all 'TopLevelCodeDecl's up to the target one.
109-
// In theory, this is not needed, but it fails to resolve the type of
110-
// 'guard'ed variable. e.g.
111-
//
112-
// guard value = something() else { fatalError() }
113-
// <complete>
114-
// Here, 'value' is '<error type>' unless we explicitly typecheck the
115-
// 'guard' statement.
116-
SourceFile *SF = DC->getParentSourceFile();
117-
for (auto *D : SF->getTopLevelDecls()) {
118-
if (auto Code = dyn_cast<TopLevelCodeDecl>(D)) {
119-
typeCheckTopLevelCodeDecl(Code);
120-
if (Code == TLCD)
121-
break;
122-
}
123-
}
108+
typeCheckTopLevelCodeDecl(TLCD);
124109
} else {
125110
typeCheckContextImpl(DC, Loc);
126111
}
@@ -882,10 +867,10 @@ class ExprContextAnalyzer {
882867
break;
883868
}
884869
default:
885-
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
886-
assert(isSingleExpressionBodyForCodeCompletion(AFD->getBody()));
870+
if (auto *FD = dyn_cast<FuncDecl>(D)) {
871+
assert(isSingleExpressionBodyForCodeCompletion(FD->getBody()));
887872
singleExpressionBody = true;
888-
recordPossibleType(getReturnTypeFromContext(AFD));
873+
recordPossibleType(getReturnTypeFromContext(FD));
889874
break;
890875
}
891876
llvm_unreachable("Unhandled decl kind.");
@@ -1019,8 +1004,8 @@ class ExprContextAnalyzer {
10191004
case DeclKind::PatternBinding:
10201005
return true;
10211006
default:
1022-
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D))
1023-
if (auto *body = AFD->getBody())
1007+
if (auto *FD = dyn_cast<FuncDecl>(D))
1008+
if (auto *body = FD->getBody())
10241009
return isSingleExpressionBodyForCodeCompletion(body);
10251010
return false;
10261011
}

lib/IDE/ExprContextAnalysis.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ enum class SemanticContextKind;
2828

2929
/// Type check parent contexts of the given decl context, and the body of the
3030
/// given context until \c Loc if the context is a function body.
31-
void typeCheckContextUntil(DeclContext *DC, SourceLoc Loc);
31+
void typeCheckContextAt(DeclContext *DC, SourceLoc Loc);
3232

3333
/// From \p DC, find and returns the outer most expression which source range is
3434
/// exact the same as \p TargetRange. Returns \c nullptr if not found.

lib/IDE/TypeContextInfo.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,7 @@ void ContextInfoCallbacks::doneParsing() {
8989
if (!ParsedExpr)
9090
return;
9191

92-
typeCheckContextUntil(
93-
CurDeclContext,
94-
CurDeclContext->getASTContext().SourceMgr.getCodeCompletionLoc());
92+
typeCheckContextAt(CurDeclContext, ParsedExpr->getLoc());
9593

9694
ExprContextInfo Info(CurDeclContext, ParsedExpr);
9795

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2355,23 +2355,23 @@ bool TypeChecker::typeCheckBinding(
23552355
if (!initializer->getType())
23562356
initializer->setType(ErrorType::get(Context));
23572357

2358-
// If the type of the pattern is inferred, assign error types to the pattern
2359-
// and its variables, to prevent it from being referenced by the constraint
2360-
// system.
2358+
// Assign error types to the pattern and its variables, to prevent it from
2359+
// being referenced by the constraint system.
23612360
if (patternType->hasUnresolvedType() ||
23622361
patternType->hasUnboundGenericType()) {
23632362
pattern->setType(ErrorType::get(Context));
2364-
pattern->forEachVariable([&](VarDecl *var) {
2365-
// Don't change the type of a variable that we've been able to
2366-
// compute a type for.
2367-
if (var->hasInterfaceType() &&
2368-
!var->getType()->hasUnboundGenericType() &&
2369-
!var->isInvalid())
2370-
return;
2371-
2372-
var->setInvalid();
2373-
});
23742363
}
2364+
2365+
pattern->forEachVariable([&](VarDecl *var) {
2366+
// Don't change the type of a variable that we've been able to
2367+
// compute a type for.
2368+
if (var->hasInterfaceType() &&
2369+
!var->getType()->hasUnboundGenericType() &&
2370+
!var->isInvalid())
2371+
return;
2372+
2373+
var->setInvalid();
2374+
});
23752375
return true;
23762376
}
23772377

@@ -2492,18 +2492,20 @@ bool TypeChecker::typeCheckCondition(Expr *&expr, DeclContext *dc) {
24922492
return !resultTy;
24932493
}
24942494

2495-
bool TypeChecker::typeCheckStmtCondition(StmtCondition &cond, DeclContext *dc,
2496-
Diag<> diagnosticForAlwaysTrue) {
2495+
bool TypeChecker::typeCheckConditionForStatement(LabeledConditionalStmt *stmt,
2496+
DeclContext *dc) {
24972497
auto &Context = dc->getASTContext();
24982498
bool hadError = false;
24992499
bool hadAnyFalsable = false;
2500+
auto cond = stmt->getCond();
25002501
for (auto &elt : cond) {
25012502
if (elt.getKind() == StmtConditionElement::CK_Availability) {
25022503
hadAnyFalsable = true;
25032504
continue;
25042505
}
25052506

25062507
if (auto E = elt.getBooleanOrNull()) {
2508+
assert(!E->getType() && "the bool condition is already type checked");
25072509
hadError |= typeCheckCondition(E, dc);
25082510
elt.setBoolean(E);
25092511
hadAnyFalsable = true;
@@ -2528,8 +2530,10 @@ bool TypeChecker::typeCheckStmtCondition(StmtCondition &cond, DeclContext *dc,
25282530
};
25292531

25302532
// Resolve the pattern.
2533+
assert(!elt.getPattern()->hasType() &&
2534+
"the pattern binding condition is already type checked");
25312535
auto *pattern = TypeChecker::resolvePattern(elt.getPattern(), dc,
2532-
/*isStmtCondition*/true);
2536+
/*isStmtCondition*/ true);
25332537
if (!pattern) {
25342538
typeCheckPatternFailed();
25352539
continue;
@@ -2554,13 +2558,28 @@ bool TypeChecker::typeCheckStmtCondition(StmtCondition &cond, DeclContext *dc,
25542558
hadAnyFalsable |= pattern->isRefutablePattern();
25552559
}
25562560

2557-
25582561
// If the binding is not refutable, and there *is* an else, reject it as
25592562
// unreachable.
25602563
if (!hadAnyFalsable && !hadError) {
25612564
auto &diags = dc->getASTContext().Diags;
2562-
diags.diagnose(cond[0].getStartLoc(), diagnosticForAlwaysTrue);
2565+
Diag<> msg = diag::invalid_diagnostic;
2566+
switch (stmt->getKind()) {
2567+
case StmtKind::If:
2568+
msg = diag::if_always_true;
2569+
break;
2570+
case StmtKind::While:
2571+
msg = diag::while_always_true;
2572+
break;
2573+
case StmtKind::Guard:
2574+
msg = diag::guard_always_succeeds;
2575+
break;
2576+
default:
2577+
llvm_unreachable("unknown LabeledConditionalStmt kind");
2578+
}
2579+
diags.diagnose(cond[0].getStartLoc(), msg);
25632580
}
2581+
2582+
stmt->setCond(cond);
25642583
return false;
25652584
}
25662585

0 commit comments

Comments
 (0)