Skip to content

Commit f212dd8

Browse files
committed
[CodeComplete] Fix a crash when completing in the signature of a function annotated with result builder
When we are completing inside a function signature, the function doesn’t have a body. We were still running `PreCheckResultBuilderApplication`, which crashed if the body was `nullptr`. rdar://111489024
1 parent 4d4b1fc commit f212dd8

File tree

2 files changed

+35
-19
lines changed

2 files changed

+35
-19
lines changed

lib/Sema/TypeCheckStmt.cpp

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2583,26 +2583,31 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
25832583
// Function builder function doesn't support partial type checking.
25842584
if (auto *func = dyn_cast<FuncDecl>(DC)) {
25852585
if (Type builderType = getResultBuilderType(func)) {
2586-
auto optBody = TypeChecker::applyResultBuilderBodyTransform(
2587-
func, builderType,
2588-
/*ClosuresInResultBuilderDontParticipateInInference=*/
2589-
ctx.CompletionCallback == nullptr && ctx.SolutionCallback == nullptr);
2590-
if ((ctx.CompletionCallback && ctx.CompletionCallback->gotCallback()) || (ctx.SolutionCallback && ctx.SolutionCallback->gotCallback())) {
2591-
// We already informed the completion callback of solutions found by
2592-
// type checking the entire result builder from
2593-
// applyResultBuilderBodyTransform. No need to typecheck the requested
2594-
// AST node individually anymore.
2595-
return false;
2596-
}
2597-
if (!ctx.CompletionCallback && !ctx.SolutionCallback && optBody && *optBody) {
2598-
// Wire up the function body now.
2599-
func->setBody(*optBody, AbstractFunctionDecl::BodyKind::TypeChecked);
2600-
return false;
2586+
if (func->getBody()) {
2587+
auto optBody = TypeChecker::applyResultBuilderBodyTransform(
2588+
func, builderType,
2589+
/*ClosuresInResultBuilderDontParticipateInInference=*/
2590+
ctx.CompletionCallback == nullptr &&
2591+
ctx.SolutionCallback == nullptr);
2592+
if ((ctx.CompletionCallback && ctx.CompletionCallback->gotCallback()) ||
2593+
(ctx.SolutionCallback && ctx.SolutionCallback->gotCallback())) {
2594+
// We already informed the completion callback of solutions found by
2595+
// type checking the entire result builder from
2596+
// applyResultBuilderBodyTransform. No need to typecheck the requested
2597+
// AST node individually anymore.
2598+
return false;
2599+
}
2600+
if (!ctx.CompletionCallback && !ctx.SolutionCallback && optBody &&
2601+
*optBody) {
2602+
// Wire up the function body now.
2603+
func->setBody(*optBody, AbstractFunctionDecl::BodyKind::TypeChecked);
2604+
return false;
2605+
}
2606+
// We did not find a solution while applying the result builder,
2607+
// possibly because the result builder contained an invalid element and
2608+
// thus the transform couldn't be applied. Perform code completion
2609+
// pretending there was no result builder to recover.
26012610
}
2602-
// We did not find a solution while applying the result builder, possibly
2603-
// because the result builder contained an invalid element and thus the
2604-
// transform couldn't be applied. Perform code completion pretending there
2605-
// was no result builder to recover.
26062611
} else if (func->hasSingleExpressionBody() &&
26072612
func->getResultInterfaceType()->isVoid()) {
26082613
// The function returns void. We don't need an explicit return, no matter
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t
3+
4+
@resultBuilder struct MyBuilder {
5+
static func buildBlock() -> Int
6+
static func buildBlock<Content>(_ content: Content) -> Content
7+
}
8+
9+
@MyBuilder func test(action: () -> #^COMPLETE^#Void) {}
10+
11+
// COMPLETE: Decl[TypeAlias]/OtherModule[Swift]/IsSystem: Void[#Void#]; name=Void

0 commit comments

Comments
 (0)