Skip to content

[CodeCompletion] Fast completion inside function builder function #32946

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions include/swift/AST/Stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -1353,6 +1353,13 @@ class PoundAssertStmt : public Stmt {
}
};

inline void simple_display(llvm::raw_ostream &out, Stmt *S) {
if (S)
out << Stmt::getKindName(S->getKind());
else
out << "(null)";
};

} // end namespace swift

#endif // SWIFT_AST_STMT_H
7 changes: 4 additions & 3 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -1836,7 +1836,8 @@ enum class FunctionBuilderBodyPreCheck : uint8_t {

class PreCheckFunctionBuilderRequest
: public SimpleRequest<PreCheckFunctionBuilderRequest,
FunctionBuilderBodyPreCheck(AnyFunctionRef),
FunctionBuilderBodyPreCheck(AnyFunctionRef,
BraceStmt *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
Expand All @@ -1845,8 +1846,8 @@ class PreCheckFunctionBuilderRequest
friend SimpleRequest;

// Evaluation.
FunctionBuilderBodyPreCheck
evaluate(Evaluator &evaluator, AnyFunctionRef fn) const;
FunctionBuilderBodyPreCheck evaluate(Evaluator &evaluator, AnyFunctionRef fn,
BraceStmt *body) const;

public:
// Separate caching.
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ SWIFT_REQUEST(TypeChecker, HasUserDefinedDesignatedInitRequest,
SWIFT_REQUEST(TypeChecker, HasMemberwiseInitRequest,
bool(StructDecl *), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, PreCheckFunctionBuilderRequest,
FunctionBuilderClosurePreCheck(AnyFunctionRef),
FunctionBuilderClosurePreCheck(AnyFunctionRef, BraceStmt *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ResolveImplicitMemberRequest,
evaluator::SideEffect(NominalTypeDecl *, ImplicitMemberAction),
Expand Down
14 changes: 10 additions & 4 deletions lib/Sema/BuilderTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1453,7 +1453,7 @@ Optional<BraceStmt *> TypeChecker::applyFunctionBuilderBodyTransform(
// If we encountered an error or there was an explicit result type,
// bail out and report that to the caller.
auto &ctx = func->getASTContext();
auto request = PreCheckFunctionBuilderRequest{func};
auto request = PreCheckFunctionBuilderRequest{func, func->getBody()};
switch (evaluateOrDefault(
ctx.evaluator, request, FunctionBuilderBodyPreCheck::Error)) {
case FunctionBuilderBodyPreCheck::Okay:
Expand Down Expand Up @@ -1581,7 +1581,7 @@ ConstraintSystem::matchFunctionBuilder(

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

FunctionBuilderBodyPreCheck
PreCheckFunctionBuilderRequest::evaluate(Evaluator &eval,
AnyFunctionRef fn) const {
PreCheckFunctionBuilderRequest::evaluate(Evaluator &eval, AnyFunctionRef fn,
BraceStmt *body) const {
// NOTE: 'body' is passed only for the request evaluater caching key.
// Since source tooling (e.g. code completion) might replace the body,
// the function alone is not sufficient for the key.
assert(fn.getBody() == body &&
"body must be the current body of the function");

// We don't want to do the precheck if it will already have happened in
// the enclosing expression.
bool skipPrecheck = false;
Expand Down
51 changes: 51 additions & 0 deletions test/SourceKit/CodeComplete/complete_sequence_builderfunc.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
protocol Entity {}
struct Empty: Entity {
var value: Void = ()
}

@_functionBuilder
struct Builder {
static func buildBlock() -> { Empty() }
static func buildBlock<T: Entity>(_ t: T) -> T { t }
}

struct MyValue {
var id: Int
var title: String
}

func build(_ arg: (MyValue) -> String) -> Empty { Empty() }

struct MyStruct {
@Builder var body: some Entity {
build { value in
value./*HERE * 2*/
} /*HERE*/
}
}

// RUN: %sourcekitd-test \
// RUN: -req=complete -pos=22:13 %s -- %s == \
// RUN: -req=complete -pos=22:13 %s -- %s == \
// RUN: -req=complete -pos=23:7 %s -- %s \
// RUN: | tee %t.result | %FileCheck %s

// CHECK-LABEL: key.results: [
// CHECK-DAG: key.description: "id"
// CHECK-DAG: key.description: "title"
// CHECK-DAG: key.description: "self"
// CHECK: ]
// CHECK-NOT: key.reusingastcontext: 1

// CHECK-LABEL: key.results: [
// CHECK-DAG: key.description: "id"
// CHECK-DAG: key.description: "title"
// CHECK-DAG: key.description: "self"
// CHECK: ]
// CHECK: key.reusingastcontext: 1

// CHECK-LABEL: key.results: [
// CHECK-DAG: key.description: "value"
// CHECK: ]
// CHECK: key.reusingastcontext: 1