Skip to content

Commit e953e52

Browse files
committed
[CodeCompletion] Fast completion inside function builder function
`PreCheckFunctionBuilderRequest` applies `PreCheckExpression` to the expressions inside the function body. Previously it used to receive only `AnyFunctionRef` (`FunctionDecl` or `ClosureExpr`) as the parameter. However, when fast-completion kicks-in, it replaces the body of the function, then tries to call `PreCheckFunctionBuilderRequest` again, with the same function decl as before. It used to return cached "Success" result, but it didn't actually apply `PreCheckExpression`. So any `UnresolvedDeclRefExpr` remained unresolved. In this patch, make `PreCheckFunctionBuilderRequest` receive "body" of the function as well, so it doesn't return the cached result for the *previous* body. rdar://problem/65692922
1 parent e51eaef commit e953e52

File tree

5 files changed

+73
-8
lines changed

5 files changed

+73
-8
lines changed

include/swift/AST/Stmt.h

+7
Original file line numberDiff line numberDiff line change
@@ -1353,6 +1353,13 @@ class PoundAssertStmt : public Stmt {
13531353
}
13541354
};
13551355

1356+
inline void simple_display(llvm::raw_ostream &out, Stmt *S) {
1357+
if (S)
1358+
out << Stmt::getKindName(S->getKind());
1359+
else
1360+
out << "(null)";
1361+
};
1362+
13561363
} // end namespace swift
13571364

13581365
#endif // SWIFT_AST_STMT_H

include/swift/AST/TypeCheckRequests.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -1836,7 +1836,8 @@ enum class FunctionBuilderBodyPreCheck : uint8_t {
18361836

18371837
class PreCheckFunctionBuilderRequest
18381838
: public SimpleRequest<PreCheckFunctionBuilderRequest,
1839-
FunctionBuilderBodyPreCheck(AnyFunctionRef),
1839+
FunctionBuilderBodyPreCheck(AnyFunctionRef,
1840+
BraceStmt *),
18401841
RequestFlags::Cached> {
18411842
public:
18421843
using SimpleRequest::SimpleRequest;
@@ -1845,8 +1846,8 @@ class PreCheckFunctionBuilderRequest
18451846
friend SimpleRequest;
18461847

18471848
// Evaluation.
1848-
FunctionBuilderBodyPreCheck
1849-
evaluate(Evaluator &evaluator, AnyFunctionRef fn) const;
1849+
FunctionBuilderBodyPreCheck evaluate(Evaluator &evaluator, AnyFunctionRef fn,
1850+
BraceStmt *body) const;
18501851

18511852
public:
18521853
// Separate caching.

include/swift/AST/TypeCheckerTypeIDZone.def

+1-1
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ SWIFT_REQUEST(TypeChecker, HasUserDefinedDesignatedInitRequest,
231231
SWIFT_REQUEST(TypeChecker, HasMemberwiseInitRequest,
232232
bool(StructDecl *), Cached, NoLocationInfo)
233233
SWIFT_REQUEST(TypeChecker, PreCheckFunctionBuilderRequest,
234-
FunctionBuilderClosurePreCheck(AnyFunctionRef),
234+
FunctionBuilderClosurePreCheck(AnyFunctionRef, BraceStmt *),
235235
Cached, NoLocationInfo)
236236
SWIFT_REQUEST(TypeChecker, ResolveImplicitMemberRequest,
237237
evaluator::SideEffect(NominalTypeDecl *, ImplicitMemberAction),

lib/Sema/BuilderTransform.cpp

+10-4
Original file line numberDiff line numberDiff line change
@@ -1453,7 +1453,7 @@ Optional<BraceStmt *> TypeChecker::applyFunctionBuilderBodyTransform(
14531453
// If we encountered an error or there was an explicit result type,
14541454
// bail out and report that to the caller.
14551455
auto &ctx = func->getASTContext();
1456-
auto request = PreCheckFunctionBuilderRequest{func};
1456+
auto request = PreCheckFunctionBuilderRequest{func, func->getBody()};
14571457
switch (evaluateOrDefault(
14581458
ctx.evaluator, request, FunctionBuilderBodyPreCheck::Error)) {
14591459
case FunctionBuilderBodyPreCheck::Okay:
@@ -1581,7 +1581,7 @@ ConstraintSystem::matchFunctionBuilder(
15811581

15821582
// Pre-check the body: pre-check any expressions in it and look
15831583
// for return statements.
1584-
auto request = PreCheckFunctionBuilderRequest{fn};
1584+
auto request = PreCheckFunctionBuilderRequest{fn, fn.getBody()};
15851585
switch (evaluateOrDefault(getASTContext().evaluator, request,
15861586
FunctionBuilderBodyPreCheck::Error)) {
15871587
case FunctionBuilderBodyPreCheck::Okay:
@@ -1744,8 +1744,14 @@ class PreCheckFunctionBuilderApplication : public ASTWalker {
17441744
}
17451745

17461746
FunctionBuilderBodyPreCheck
1747-
PreCheckFunctionBuilderRequest::evaluate(Evaluator &eval,
1748-
AnyFunctionRef fn) const {
1747+
PreCheckFunctionBuilderRequest::evaluate(Evaluator &eval, AnyFunctionRef fn,
1748+
BraceStmt *body) const {
1749+
// NOTE: 'body' is passed only for the request evaluater caching key.
1750+
// Since source tooling (e.g. code completion) might replace the body,
1751+
// the function alone is not sufficient for the key.
1752+
assert(fn.getBody() == body &&
1753+
"body must be the current body of the function");
1754+
17491755
// We don't want to do the precheck if it will already have happened in
17501756
// the enclosing expression.
17511757
bool skipPrecheck = false;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
protocol Entity {}
2+
struct Empty: Entity {
3+
var value: Void = ()
4+
}
5+
6+
@_functionBuilder
7+
struct Builder {
8+
static func buildBlock() -> { Empty() }
9+
static func buildBlock<T: Entity>(_ t: T) -> T { t }
10+
}
11+
12+
struct MyValue {
13+
var id: Int
14+
var title: String
15+
}
16+
17+
func build(_ arg: (MyValue) -> String) -> Empty { Empty() }
18+
19+
struct MyStruct {
20+
@Builder var body: some Entity {
21+
build { value in
22+
value./*HERE * 2*/
23+
} /*HERE*/
24+
}
25+
}
26+
27+
// RUN: %sourcekitd-test \
28+
// RUN: -req=complete -pos=22:13 %s -- %s == \
29+
// RUN: -req=complete -pos=22:13 %s -- %s == \
30+
// RUN: -req=complete -pos=23:7 %s -- %s \
31+
// RUN: | tee %t.result | %FileCheck %s
32+
33+
// CHECK-LABEL: key.results: [
34+
// CHECK-DAG: key.description: "id"
35+
// CHECK-DAG: key.description: "title"
36+
// CHECK-DAG: key.description: "self"
37+
// CHECK: ]
38+
// CHECK-NOT: key.reusingastcontext: 1
39+
40+
// CHECK-LABEL: key.results: [
41+
// CHECK-DAG: key.description: "id"
42+
// CHECK-DAG: key.description: "title"
43+
// CHECK-DAG: key.description: "self"
44+
// CHECK: ]
45+
// CHECK: key.reusingastcontext: 1
46+
47+
// CHECK-LABEL: key.results: [
48+
// CHECK-DAG: key.description: "value"
49+
// CHECK: ]
50+
// CHECK: key.reusingastcontext: 1
51+

0 commit comments

Comments
 (0)