Skip to content

Commit 5919697

Browse files
authored
Merge pull request #32696 from rintaro/ide-completion-typecheckatloc
[CodeCompletion] Only type check target statement and related decls in function body
2 parents 256ec45 + 2b6ffb5 commit 5919697

21 files changed

+353
-156
lines changed

include/swift/AST/Expr.h

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3759,7 +3759,25 @@ class SerializedAbstractClosureExpr : public SerializedLocalDeclContext {
37593759
/// { [weak c] (a : Int) -> Int in a + c!.getFoo() }
37603760
/// \endcode
37613761
class ClosureExpr : public AbstractClosureExpr {
3762+
public:
3763+
enum class BodyState {
3764+
/// The body was parsed, but not ready for type checking because
3765+
/// the closure parameters haven't been type checked.
3766+
Parsed,
3767+
3768+
/// The type of the closure itself was type checked. But the body has not
3769+
/// been type checked yet.
3770+
ReadyForTypeChecking,
3771+
3772+
/// The body was typechecked with the enclosing closure.
3773+
/// i.e. single expression closure or function builder closure.
3774+
TypeCheckedWithSignature,
3775+
3776+
/// The body was type checked separately from the enclosing closure.
3777+
SeparatelyTypeChecked,
3778+
};
37623779

3780+
private:
37633781
/// The range of the brackets of the capture list, if present.
37643782
SourceRange BracketRange;
37653783

@@ -3783,8 +3801,7 @@ class ClosureExpr : public AbstractClosureExpr {
37833801
SourceLoc InLoc;
37843802

37853803
/// The explicitly-specified result type.
3786-
llvm::PointerIntPair<TypeExpr *, 1, bool>
3787-
ExplicitResultTypeAndSeparatelyChecked;
3804+
llvm::PointerIntPair<TypeExpr *, 2, BodyState> ExplicitResultTypeAndBodyState;
37883805

37893806
/// The body of the closure, along with a bit indicating whether it
37903807
/// was originally just a single expression.
@@ -3799,7 +3816,7 @@ class ClosureExpr : public AbstractClosureExpr {
37993816
BracketRange(bracketRange),
38003817
CapturedSelfDecl(capturedSelfDecl),
38013818
ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc), InLoc(inLoc),
3802-
ExplicitResultTypeAndSeparatelyChecked(explicitResultType, false),
3819+
ExplicitResultTypeAndBodyState(explicitResultType, BodyState::Parsed),
38033820
Body(nullptr) {
38043821
setParameterList(params);
38053822
Bits.ClosureExpr.HasAnonymousClosureVars = false;
@@ -3854,15 +3871,13 @@ class ClosureExpr : public AbstractClosureExpr {
38543871

38553872
Type getExplicitResultType() const {
38563873
assert(hasExplicitResultType() && "No explicit result type");
3857-
return ExplicitResultTypeAndSeparatelyChecked.getPointer()
3858-
->getInstanceType();
3874+
return ExplicitResultTypeAndBodyState.getPointer()->getInstanceType();
38593875
}
38603876
void setExplicitResultType(Type ty);
38613877

38623878
TypeRepr *getExplicitResultTypeRepr() const {
38633879
assert(hasExplicitResultType() && "No explicit result type");
3864-
return ExplicitResultTypeAndSeparatelyChecked.getPointer()
3865-
->getTypeRepr();
3880+
return ExplicitResultTypeAndBodyState.getPointer()->getTypeRepr();
38663881
}
38673882

38683883
/// Determine whether the closure has a single expression for its
@@ -3904,14 +3919,20 @@ class ClosureExpr : public AbstractClosureExpr {
39043919
/// captured non-weakly).
39053920
bool capturesSelfEnablingImplictSelf() const;
39063921

3907-
/// Whether this closure's body was type checked separately from its
3908-
/// enclosing expression.
3909-
bool wasSeparatelyTypeChecked() const {
3910-
return ExplicitResultTypeAndSeparatelyChecked.getInt();
3922+
3923+
/// Get the type checking state of this closure's body.
3924+
BodyState getBodyState() const {
3925+
return ExplicitResultTypeAndBodyState.getInt();
3926+
}
3927+
void setBodyState(BodyState v) {
3928+
ExplicitResultTypeAndBodyState.setInt(v);
39113929
}
39123930

3913-
void setSeparatelyTypeChecked(bool flag = true) {
3914-
ExplicitResultTypeAndSeparatelyChecked.setInt(flag);
3931+
/// Whether this closure's body is/was type checked separately from its
3932+
/// enclosing expression.
3933+
bool isSeparatelyTypeChecked() const {
3934+
return getBodyState() == BodyState::SeparatelyTypeChecked ||
3935+
getBodyState() == BodyState::ReadyForTypeChecking;
39153936
}
39163937

39173938
static bool classof(const Expr *E) {

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: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ namespace swift {
514514
/// Indicate that the type checker should skip type-checking non-inlinable
515515
/// function bodies.
516516
bool SkipNonInlinableFunctionBodies = false;
517-
517+
518518
///
519519
/// Flags for developers
520520
///

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/ASTWalker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -833,7 +833,7 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
833833

834834
// If the closure was separately type checked and we don't want to
835835
// visit separately-checked closure bodies, bail out now.
836-
if (expr->wasSeparatelyTypeChecked() &&
836+
if (expr->isSeparatelyTypeChecked() &&
837837
!Walker.shouldWalkIntoSeparatelyCheckedClosure(expr))
838838
return expr;
839839

lib/AST/Expr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1996,7 +1996,7 @@ bool ClosureExpr::capturesSelfEnablingImplictSelf() const {
19961996

19971997
void ClosureExpr::setExplicitResultType(Type ty) {
19981998
assert(ty && !ty->hasTypeVariable());
1999-
ExplicitResultTypeAndSeparatelyChecked.getPointer()
1999+
ExplicitResultTypeAndBodyState.getPointer()
20002000
->setType(MetatypeType::get(ty));
20012001
}
20022002

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: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4129,6 +4129,10 @@ namespace {
41294129
// If we end up here, we should have diagnosed somewhere else
41304130
// already.
41314131
Expr *simplified = simplifyExprType(expr);
4132+
// Invalidate 'VarDecl's inside the pattern.
4133+
expr->getSubPattern()->forEachVariable([](VarDecl *VD) {
4134+
VD->setInvalid();
4135+
});
41324136
if (!SuppressDiagnostics
41334137
&& !cs.getType(simplified)->is<UnresolvedType>()) {
41344138
auto &de = cs.getASTContext().Diags;
@@ -7834,8 +7838,11 @@ namespace {
78347838
return true;
78357839

78367840
case SolutionApplicationToFunctionResult::Delay: {
7837-
auto closure = cast<ClosureExpr>(fn.getAbstractClosureExpr());
7838-
ClosuresToTypeCheck.push_back(closure);
7841+
if (!Rewriter.cs.Options
7842+
.contains(ConstraintSystemFlags::LeaveClosureBodyUnchecked)) {
7843+
auto closure = cast<ClosureExpr>(fn.getAbstractClosureExpr());
7844+
ClosuresToTypeCheck.push_back(closure);
7845+
}
78397846
return false;
78407847
}
78417848
}
@@ -8414,6 +8421,7 @@ Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
84148421

84158422
// Visit closures that have non-single expression bodies.
84168423
bool hadError = false;
8424+
84178425
for (auto *closure : walker.getClosuresToTypeCheck())
84188426
hadError |= TypeChecker::typeCheckClosureBody(closure);
84198427

lib/Sema/CSClosure.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,11 +345,13 @@ SolutionApplicationToFunctionResult ConstraintSystem::applySolution(
345345
ClosureConstraintApplication application(
346346
solution, closure, closureFnType->getResult(), rewriteTarget);
347347
application.visit(fn.getBody());
348+
closure->setBodyState(ClosureExpr::BodyState::TypeCheckedWithSignature);
348349

349350
return SolutionApplicationToFunctionResult::Success;
350351
}
351352

352353
// Otherwise, we need to delay type checking of the closure until later.
353354
solution.setExprTypes(closure);
355+
closure->setBodyState(ClosureExpr::BodyState::ReadyForTypeChecking);
354356
return SolutionApplicationToFunctionResult::Delay;
355357
}

lib/Sema/ConstraintSystem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,10 @@ enum class ConstraintSystemFlags {
12501250
/// for a pre-configured set of expressions on line numbers by setting
12511251
/// \c DebugConstraintSolverOnLines.
12521252
DebugConstraints = 0x10,
1253+
1254+
/// Don't try to type check closure bodies, and leave them unchecked. This is
1255+
/// used for source tooling functionalities.
1256+
LeaveClosureBodyUnchecked = 0x20,
12531257
};
12541258

12551259
/// Options that affect the constraint system as a whole.

lib/Sema/MiscDiagnostics.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
8686

8787
bool walkToDeclPre(Decl *D) override {
8888
if (auto *closure = dyn_cast<ClosureExpr>(D->getDeclContext()))
89-
return !closure->wasSeparatelyTypeChecked();
89+
return !closure->isSeparatelyTypeChecked();
9090
return false;
9191
}
9292

@@ -1501,7 +1501,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
15011501
// Don't walk into nested decls.
15021502
bool walkToDeclPre(Decl *D) override {
15031503
if (auto *closure = dyn_cast<ClosureExpr>(D->getDeclContext()))
1504-
return !closure->wasSeparatelyTypeChecked();
1504+
return !closure->isSeparatelyTypeChecked();
15051505
return false;
15061506
}
15071507

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1136,7 +1136,7 @@ static void findAvailabilityFixItNodes(SourceRange ReferenceRange,
11361136
if (Expr *ParentExpr = Parent.getAsExpr()) {
11371137
auto *ParentClosure = dyn_cast<ClosureExpr>(ParentExpr);
11381138
if (!ParentClosure ||
1139-
ParentClosure->wasSeparatelyTypeChecked()) {
1139+
ParentClosure->isSeparatelyTypeChecked()) {
11401140
return false;
11411141
}
11421142
} else if (auto *ParentStmt = Parent.getAsStmt()) {

0 commit comments

Comments
 (0)