Skip to content

Commit 12762a2

Browse files
committed
[CodeCompletion] Only type check related statements in function body
Introduce 'TypeCheckSingleASTNode' mode that only type checks single body element and dependent necessities (i.e. referencing ValueDecls and their dependencies). Renamed swift::typeCheckAbstractFunctionBodyAtLoc() to swift::typeCheckASTNodeAtLoc(DeclContext *, SourceLoc). That type checks innermost 'ASTNode' at the location. Also, 'TypeCheckSingleASTNode' mode skips type checking any "body" of the node (i.e. BraceStmt elements for function body, if statement body, closure body, etc.) Added on-demand type checking using it: - VarDecl in TapExpr - ParamDecl in ClosureExpr - Return type of ClosureExpr - Binding value in control statements (e.g. ForEachStmt, SwitchStmt, DoCatchStmt, etc.) rdar://problem/63932852
1 parent c6b7ff3 commit 12762a2

17 files changed

+244
-78
lines changed

include/swift/AST/Expr.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -950,11 +950,9 @@ class TapExpr : public Expr {
950950
BraceStmt * getBody() const { return Body; }
951951
void setBody(BraceStmt * b) { Body = b; }
952952

953-
SourceLoc getLoc() const { return SubExpr ? SubExpr->getLoc() : SourceLoc(); }
953+
SourceLoc getLoc() const { return getStartLoc(); }
954954

955-
SourceLoc getStartLoc() const {
956-
return SubExpr ? SubExpr->getStartLoc() : SourceLoc();
957-
}
955+
SourceLoc getStartLoc() const;
958956

959957
SourceLoc getEndLoc() const;
960958

include/swift/AST/TypeCheckRequests.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -892,9 +892,9 @@ class TypeCheckFunctionBodyRequest :
892892
/// Request to typecheck a function body element at the given source location.
893893
///
894894
/// Produces true if an error occurred, false otherwise.
895-
class TypeCheckFunctionBodyAtLocRequest
896-
: public SimpleRequest<TypeCheckFunctionBodyAtLocRequest,
897-
bool(AbstractFunctionDecl *, SourceLoc),
895+
class TypeCheckASTNodeAtLocRequest
896+
: public SimpleRequest<TypeCheckASTNodeAtLocRequest,
897+
bool(DeclContext *, SourceLoc),
898898
RequestFlags::Uncached> {
899899
public:
900900
using SimpleRequest::SimpleRequest;
@@ -903,8 +903,7 @@ class TypeCheckFunctionBodyAtLocRequest
903903
friend SimpleRequest;
904904

905905
// Evaluation.
906-
bool evaluate(Evaluator &evaluator, AbstractFunctionDecl *func,
907-
SourceLoc Loc) const;
906+
bool evaluate(Evaluator &evaluator, DeclContext *DC, SourceLoc Loc) const;
908907
};
909908

910909
/// Request to obtain a list of stored properties in a nominal type.

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,8 @@ SWIFT_REQUEST(TypeChecker, TangentStoredPropertyRequest,
207207
llvm::Expected<VarDecl *>(VarDecl *, CanType), Cached, NoLocationInfo)
208208
SWIFT_REQUEST(TypeChecker, TypeCheckFunctionBodyRequest,
209209
bool(AbstractFunctionDecl *), Cached, NoLocationInfo)
210-
SWIFT_REQUEST(TypeChecker, TypeCheckFunctionBodyAtLocRequest,
211-
bool(AbstractFunctionDecl *, SourceLoc),
210+
SWIFT_REQUEST(TypeChecker, TypeCheckASTNodeAtLocRequest,
211+
bool(DeclContext *, SourceLoc),
212212
Uncached, NoLocationInfo)
213213
SWIFT_REQUEST(TypeChecker, UnderlyingTypeRequest, Type(TypeAliasDecl *),
214214
SeparatelyCached, NoLocationInfo)

include/swift/Basic/LangOptions.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,10 @@ namespace swift {
507507
/// Indicate that the type checker should skip type-checking non-inlinable
508508
/// function bodies.
509509
bool SkipNonInlinableFunctionBodies = false;
510-
510+
511+
/// Single statement (ASTNode) type checking mode for IDE tooling.
512+
bool TypeCheckSingleASTNode = false;
513+
511514
///
512515
/// Flags for developers
513516
///

include/swift/Sema/IDETypeChecking.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,7 @@ namespace swift {
133133
bool typeCheckExpression(DeclContext *DC, Expr *&parsedExpr);
134134

135135
/// Type check a function body element which is at \p TagetLoc .
136-
bool typeCheckAbstractFunctionBodyAtLoc(AbstractFunctionDecl *AFD,
137-
SourceLoc TargetLoc);
136+
bool typeCheckASTNodeAtLoc(DeclContext *DC, SourceLoc TargetLoc);
138137

139138
/// Typecheck top-level code parsed during code completion.
140139
///

lib/AST/Expr.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2398,6 +2398,15 @@ VarDecl * TapExpr::getVar() const {
23982398
return dyn_cast<VarDecl>(Body->getFirstElement().dyn_cast<Decl *>());
23992399
}
24002400

2401+
SourceLoc TapExpr::getStartLoc() const {
2402+
// Include the body in the range, assuming the body follows the SubExpr.
2403+
if (auto *const se = getSubExpr())
2404+
return se->getStartLoc();
2405+
if (auto *const b = getBody())
2406+
return b->getStartLoc();
2407+
return SourceLoc();
2408+
}
2409+
24012410
SourceLoc TapExpr::getEndLoc() const {
24022411
// Include the body in the range, assuming the body follows the SubExpr.
24032412
// Also, be (perhaps overly) defensive about null pointers & invalid

lib/IDE/CompletionInstance.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,9 @@ bool CompletionInstance::performNewOperation(
520520

521521
Invocation.setCodeCompletionPoint(completionBuffer, Offset);
522522

523+
// Enable single ASTNode type checking mode.
524+
Invocation.getTypeCheckerOptions().TypeCheckSingleASTNode = true;
525+
523526
if (CI.setup(Invocation)) {
524527
Error = "failed to setup compiler instance";
525528
return false;

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,30 @@ void typeCheckContextImpl(DeclContext *DC, SourceLoc Loc) {
4848
if (DC->isModuleScopeContext())
4949
return;
5050

51-
typeCheckContextImpl(DC->getParent(), Loc);
51+
// Make sure the extension has been bound, in case it is in an inactive #if
52+
// or something weird like that.
53+
{
54+
SmallVector<ExtensionDecl *, 1> extensions;
55+
for (auto typeCtx = DC->getInnermostTypeContext(); typeCtx != nullptr;
56+
typeCtx = typeCtx->getParent()->getInnermostTypeContext()) {
57+
if (auto *ext = dyn_cast<ExtensionDecl>(typeCtx))
58+
extensions.push_back(ext);
59+
}
60+
while (!extensions.empty()) {
61+
extensions.back()->computeExtendedNominal();
62+
extensions.pop_back();
63+
}
64+
}
5265

5366
// Type-check this context.
5467
switch (DC->getContextKind()) {
5568
case DeclContextKind::AbstractClosureExpr:
5669
case DeclContextKind::Module:
5770
case DeclContextKind::SerializedLocal:
58-
case DeclContextKind::TopLevelCodeDecl:
5971
case DeclContextKind::EnumElementDecl:
6072
case DeclContextKind::GenericTypeDecl:
6173
case DeclContextKind::SubscriptDecl:
74+
case DeclContextKind::ExtensionDecl:
6275
// Nothing to do for these.
6376
break;
6477

@@ -76,25 +89,23 @@ void typeCheckContextImpl(DeclContext *DC, SourceLoc Loc) {
7689
}
7790
break;
7891

92+
case DeclContextKind::TopLevelCodeDecl:
93+
swift::typeCheckASTNodeAtLoc(DC, Loc);
94+
break;
95+
7996
case DeclContextKind::AbstractFunctionDecl: {
8097
auto *AFD = cast<AbstractFunctionDecl>(DC);
8198
auto &SM = DC->getASTContext().SourceMgr;
8299
auto bodyRange = AFD->getBodySourceRange();
83100
if (SM.rangeContainsTokenLoc(bodyRange, Loc)) {
84-
swift::typeCheckAbstractFunctionBodyAtLoc(AFD, Loc);
101+
swift::typeCheckASTNodeAtLoc(DC, Loc);
85102
} else {
86103
assert(bodyRange.isInvalid() && "The body should not be parsed if the "
87104
"completion happens in the signature");
88105
}
89106
break;
90107
}
91108

92-
case DeclContextKind::ExtensionDecl:
93-
// Make sure the extension has been bound, in case it is in an
94-
// inactive #if or something weird like that.
95-
cast<ExtensionDecl>(DC)->computeExtendedNominal();
96-
break;
97-
98109
case DeclContextKind::FileUnit:
99110
llvm_unreachable("module scope context handled above");
100111
}
@@ -105,11 +116,7 @@ void swift::ide::typeCheckContextAt(DeclContext *DC, SourceLoc Loc) {
105116
while (isa<AbstractClosureExpr>(DC))
106117
DC = DC->getParent();
107118

108-
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(DC)) {
109-
typeCheckTopLevelCodeDecl(TLCD);
110-
} else {
111-
typeCheckContextImpl(DC, Loc);
112-
}
119+
typeCheckContextImpl(DC, Loc);
113120
}
114121

115122
//===----------------------------------------------------------------------===//
@@ -300,6 +307,10 @@ void swift::ide::collectPossibleReturnTypesFromContext(
300307
}
301308

302309
if (auto ACE = dyn_cast<AbstractClosureExpr>(DC)) {
310+
// Try type checking the closure signature if it hasn't.
311+
if (!ACE->getType())
312+
swift::typeCheckASTNodeAtLoc(ACE->getParent(), ACE->getLoc());
313+
303314
// Use the type checked type if it has.
304315
if (ACE->getType() && !ACE->getType()->hasError() &&
305316
!ACE->getResultType()->hasUnresolvedType()) {

lib/Sema/CSApply.cpp

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8271,22 +8271,25 @@ Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
82718271
if (!resultTarget)
82728272
return None;
82738273

8274-
// Visit closures that have non-single expression bodies.
8275-
bool hadError = false;
8276-
for (auto *closure : walker.getClosuresToTypeCheck())
8277-
hadError |= TypeChecker::typeCheckClosureBody(closure);
8278-
8279-
// Tap expressions too; they should or should not be
8280-
// type-checked under the same conditions as closure bodies.
8281-
for (auto tuple : walker.getTapsToTypeCheck()) {
8282-
auto tap = std::get<0>(tuple);
8283-
auto tapDC = std::get<1>(tuple);
8284-
hadError |= TypeChecker::typeCheckTapBody(tap, tapDC);
8285-
}
8274+
if (!getASTContext().TypeCheckerOpts.TypeCheckSingleASTNode) {
8275+
bool hadError = false;
82868276

8287-
// If any of them failed to type check, bail.
8288-
if (hadError)
8289-
return None;
8277+
// Visit closures that have non-single expression bodies.
8278+
for (auto *closure : walker.getClosuresToTypeCheck())
8279+
hadError |= TypeChecker::typeCheckClosureBody(closure);
8280+
8281+
// Tap expressions too; they should or should not be
8282+
// type-checked under the same conditions as closure bodies.
8283+
for (auto tuple : walker.getTapsToTypeCheck()) {
8284+
auto tap = std::get<0>(tuple);
8285+
auto tapDC = std::get<1>(tuple);
8286+
hadError |= TypeChecker::typeCheckTapBody(tap, tapDC);
8287+
}
8288+
8289+
// If any of them failed to type check, bail.
8290+
if (hadError)
8291+
return None;
8292+
}
82908293

82918294
rewriter.finalize();
82928295

lib/Sema/TypeCheckDecl.cpp

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "swift/Basic/Statistic.h"
4646
#include "swift/Parse/Lexer.h"
4747
#include "swift/Parse/Parser.h"
48+
#include "swift/Sema/IDETypeChecking.h"
4849
#include "swift/Serialization/SerializedModuleLoader.h"
4950
#include "swift/Strings.h"
5051
#include "swift/AST/NameLookupRequests.h"
@@ -2233,16 +2234,35 @@ InterfaceTypeRequest::evaluate(Evaluator &eval, ValueDecl *D) const {
22332234
}
22342235
}
22352236

2236-
if (!PD->getTypeRepr())
2237-
return Type();
2237+
if (PD->getTypeRepr()) {
2238+
return validateParameterType(PD);
2239+
}
2240+
2241+
// Try type checking the closure if it hasn't.
2242+
// NOTE: Do this only in 'TypeCheckSingleASTNode' mode. Otherwise, the
2243+
// parent closure should have been type checked before.
2244+
if (Context.TypeCheckerOpts.TypeCheckSingleASTNode &&
2245+
isa<ClosureExpr>(PD->getDeclContext())) {
2246+
auto *closure = cast<ClosureExpr>(PD->getDeclContext());
2247+
if (!closure->getType()) {
2248+
swift::typeCheckASTNodeAtLoc(closure->getParent(), closure->getLoc());
2249+
if (PD->hasInterfaceType())
2250+
return PD->getInterfaceType();
2251+
}
2252+
}
22382253

2239-
return validateParameterType(PD);
2254+
// Failed.
2255+
return Type();
22402256
}
22412257

22422258
case DeclKind::Var: {
22432259
auto *VD = cast<VarDecl>(D);
22442260
Type interfaceType;
22452261
if (auto *parentE = VD->getParentExpr()) {
2262+
if (Context.TypeCheckerOpts.TypeCheckSingleASTNode &&
2263+
!parentE->getType()) {
2264+
swift::typeCheckASTNodeAtLoc(VD->getDeclContext(), parentE->getLoc());
2265+
}
22462266
interfaceType = parentE->getType();
22472267
} else if (auto *namingPattern = VD->getNamingPattern()) {
22482268
interfaceType = namingPattern->getType();
@@ -2405,13 +2425,17 @@ NamingPatternRequest::evaluate(Evaluator &evaluator, VarDecl *VD) const {
24052425
namingPattern = canVD->NamingPattern;
24062426
}
24072427

2408-
if (!namingPattern) {
2409-
// Try type checking parent conditional statement.
2428+
if (!namingPattern &&
2429+
VD->getASTContext().TypeCheckerOpts.TypeCheckSingleASTNode) {
2430+
// Try type checking parent control statement.
2431+
// NOTE: Do this only in 'TypeCheckSingleASTNode' mode. Otherwise, the
2432+
// parent control statement should have been type checked before.
24102433
if (auto parentStmt = VD->getParentPatternStmt()) {
2411-
if (auto LCS = dyn_cast<LabeledConditionalStmt>(parentStmt)) {
2412-
TypeChecker::typeCheckConditionForStatement(LCS, VD->getDeclContext());
2413-
namingPattern = VD->NamingPattern;
2414-
}
2434+
if (auto CS = dyn_cast<CaseStmt>(parentStmt))
2435+
parentStmt = CS->getParentStmt();
2436+
ASTNode node(parentStmt);
2437+
TypeChecker::typeCheckASTNode(node, VD->getDeclContext());
2438+
namingPattern = VD->getCanonicalVarDecl()->NamingPattern;
24152439
}
24162440
}
24172441

0 commit comments

Comments
 (0)