Skip to content

Commit 9e5015b

Browse files
committed
[CodeCompletion] Teach TypeCheckASTNodeAtLocRequest to check initializers
This simplifies the logic in `ide::typeCheckContextAt` and fixes an issue that prevent code completion from working inside variables that are initialized by calling a closure. Fixes rdar://90455154 [SR-16012] Fixes rdar://85600167 [SR-15495]
1 parent 73475ce commit 9e5015b

File tree

5 files changed

+70
-61
lines changed

5 files changed

+70
-61
lines changed

lib/AST/DeclContext.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,11 @@ ProtocolDecl *DeclContext::getExtendedProtocolDecl() const {
8585

8686
VarDecl *DeclContext::getNonLocalVarDecl() const {
8787
if (auto *init = dyn_cast<PatternBindingInitializer>(this)) {
88-
if (auto *var =
89-
init->getBinding()->getAnchoringVarDecl(init->getBindingIndex())) {
90-
return var;
91-
}
88+
if (auto binding = init->getBinding()) {
89+
if (auto *var = binding->getAnchoringVarDecl(init->getBindingIndex())) {
90+
return var;
91+
}
92+
}
9293
}
9394
return nullptr;
9495
}

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 1 addition & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,6 @@ using namespace ide;
4343
//===----------------------------------------------------------------------===//
4444

4545
void swift::ide::typeCheckContextAt(DeclContext *DC, SourceLoc Loc) {
46-
while (isa<AbstractClosureExpr>(DC))
47-
DC = DC->getParent();
48-
4946
// Make sure the extension has been bound.
5047
{
5148
// Even if the extension is invalid (e.g. nested in a function or another
@@ -77,60 +74,7 @@ void swift::ide::typeCheckContextAt(DeclContext *DC, SourceLoc Loc) {
7774
}
7875
}
7976

80-
// Type-check this context.
81-
switch (DC->getContextKind()) {
82-
case DeclContextKind::AbstractClosureExpr:
83-
case DeclContextKind::Module:
84-
case DeclContextKind::FileUnit:
85-
case DeclContextKind::SerializedLocal:
86-
case DeclContextKind::EnumElementDecl:
87-
case DeclContextKind::GenericTypeDecl:
88-
case DeclContextKind::SubscriptDecl:
89-
case DeclContextKind::ExtensionDecl:
90-
// Nothing to do for these.
91-
break;
92-
93-
case DeclContextKind::Initializer:
94-
if (auto *patternInit = dyn_cast<PatternBindingInitializer>(DC)) {
95-
if (auto *PBD = patternInit->getBinding()) {
96-
auto i = patternInit->getBindingIndex();
97-
PBD->getPattern(i)->forEachVariable(
98-
[](VarDecl *VD) { (void)VD->getInterfaceType(); });
99-
if (PBD->getInit(i)) {
100-
if (!PBD->isInitializerChecked(i))
101-
typeCheckPatternBinding(PBD, i,
102-
/*LeaveClosureBodyUnchecked=*/true);
103-
}
104-
}
105-
} else if (auto *defaultArg = dyn_cast<DefaultArgumentInitializer>(DC)) {
106-
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(defaultArg->getParent())) {
107-
auto *Param = AFD->getParameters()->get(defaultArg->getIndex());
108-
(void)Param->getTypeCheckedDefaultExpr();
109-
}
110-
if (auto *SD = dyn_cast<SubscriptDecl>(defaultArg->getParent())) {
111-
auto *Param = SD->getIndices()->get(defaultArg->getIndex());
112-
(void)Param->getTypeCheckedDefaultExpr();
113-
}
114-
}
115-
break;
116-
117-
case DeclContextKind::TopLevelCodeDecl:
118-
swift::typeCheckASTNodeAtLoc(DC, Loc);
119-
break;
120-
121-
case DeclContextKind::AbstractFunctionDecl: {
122-
auto *AFD = cast<AbstractFunctionDecl>(DC);
123-
auto &SM = DC->getASTContext().SourceMgr;
124-
auto bodyRange = AFD->getBodySourceRange();
125-
if (SM.rangeContainsTokenLoc(bodyRange, Loc)) {
126-
swift::typeCheckASTNodeAtLoc(DC, Loc);
127-
} else {
128-
assert(bodyRange.isInvalid() && "The body should not be parsed if the "
129-
"completion happens in the signature");
130-
}
131-
break;
132-
}
133-
}
77+
swift::typeCheckASTNodeAtLoc(DC, Loc);
13478
}
13579

13680
//===----------------------------------------------------------------------===//

lib/Sema/TypeCheckStmt.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1800,6 +1800,36 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(Evaluator &evaluator,
18001800
assert(DiagnosticSuppression::isEnabled(ctx.Diags) &&
18011801
"Diagnosing and Single ASTNode type checknig don't mix");
18021802

1803+
// Initializers aren't walked by ASTWalker and thus we don't find the context
1804+
// to type check using ASTNodeFinder. Also, initializers aren't representable
1805+
// by ASTNodes that can be type checked using typeCheckASTNode.
1806+
// Handle them specifically here.
1807+
if (auto *patternInit = dyn_cast<PatternBindingInitializer>(DC)) {
1808+
if (auto *PBD = patternInit->getBinding()) {
1809+
auto i = patternInit->getBindingIndex();
1810+
PBD->getPattern(i)->forEachVariable(
1811+
[](VarDecl *VD) { (void)VD->getInterfaceType(); });
1812+
if (PBD->getInit(i)) {
1813+
if (!PBD->isInitializerChecked(i)) {
1814+
typeCheckPatternBinding(PBD, i,
1815+
/*LeaveClosureBodyUnchecked=*/true);
1816+
return false;
1817+
}
1818+
}
1819+
}
1820+
} else if (auto *defaultArg = dyn_cast<DefaultArgumentInitializer>(DC)) {
1821+
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(defaultArg->getParent())) {
1822+
auto *Param = AFD->getParameters()->get(defaultArg->getIndex());
1823+
(void)Param->getTypeCheckedDefaultExpr();
1824+
return false;
1825+
}
1826+
if (auto *SD = dyn_cast<SubscriptDecl>(defaultArg->getParent())) {
1827+
auto *Param = SD->getIndices()->get(defaultArg->getIndex());
1828+
(void)Param->getTypeCheckedDefaultExpr();
1829+
return false;
1830+
}
1831+
}
1832+
18031833
// Find innermost ASTNode at Loc from DC. Results the reference to the found
18041834
// ASTNode and the decl context of it.
18051835
class ASTNodeFinder : public ASTWalker {

test/IDE/complete_call_arg.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,3 +1382,20 @@ func testTopLevelFuncWithErrorParam() {
13821382
// TOP_LEVEL_FUNC_WITH_ERROR_PARAM-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): A#})[#(into: inout Hasher) -> Void#]; name=hash(:)
13831383
// TOP_LEVEL_FUNC_WITH_ERROR_PARAM: End completions
13841384
}
1385+
1386+
func testVarInitializedByCallingClosure() {
1387+
struct MyBundle {
1388+
func vrl(forResource: String, withExtension: String?)
1389+
}
1390+
1391+
struct Foo {
1392+
private lazy var calculatorContext: Void = {
1393+
let Bundle_main = MyBundle()
1394+
Bundle_main.vrl(forResource: "turnips", #^VAR_INITIALIZED_BY_CALLING_CLOSURE^#withExtension: "js")
1395+
}()
1396+
}
1397+
1398+
// VAR_INITIALIZED_BY_CALLING_CLOSURE: Begin completions, 1 items
1399+
// VAR_INITIALIZED_BY_CALLING_CLOSURE-DAG: Pattern/Local/Flair[ArgLabels]: {#withExtension: String?#}[#String?#];
1400+
// VAR_INITIALIZED_BY_CALLING_CLOSURE: End completions
1401+
}

test/IDE/complete_multiple_files.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
//
1010
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=MODULE_SCOPED %S/Inputs/multiple-files-1.swift %S/Inputs/multiple-files-2.swift | %FileCheck %s -check-prefix=MODULE_SCOPED
1111

12+
// RUN: %empty-directory(%t)
13+
// RUN: echo "" > %t/empty.swift
14+
// RUN: %swift-ide-test --code-completion --code-completion-token VAR_INITIALIZED_BY_CALLING_CLOSURE --source-filename %s --second-source-filename %t/empty.swift | %FileCheck %s -check-prefix=VAR_INITIALIZED_BY_CALLING_CLOSURE
15+
1216
func testObjectExpr() {
1317
fooObject.#^T1^#
1418
}
@@ -45,3 +49,16 @@ func moduleScoped() {
4549
// MODULE_SCOPED: Decl[Struct]/CurrModule: FooStruct[#FooStruct#]{{; name=.+$}}
4650
// MODULE_SCOPED-NOT: ERROR
4751
// MODULE_SCOPED: End completions
52+
53+
enum Foo {
54+
case bar
55+
}
56+
57+
var sr15495: Void = {
58+
let foo: Foo = .#^VAR_INITIALIZED_BY_CALLING_CLOSURE^#
59+
}()
60+
61+
// VAR_INITIALIZED_BY_CALLING_CLOSURE: Begin completions, 2 items
62+
// VAR_INITIALIZED_BY_CALLING_CLOSURE-DAG: Decl[EnumElement]/CurrNominal/Flair[ExprSpecific]/TypeRelation[Identical]: bar[#Foo#];
63+
// VAR_INITIALIZED_BY_CALLING_CLOSURE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): Foo#})[#(into: inout Hasher) -> Void#];
64+
// VAR_INITIALIZED_BY_CALLING_CLOSURE: End completions

0 commit comments

Comments
 (0)