Skip to content

Commit 4d1e44f

Browse files
committed
[CodeCompletion] Don't typecheck expression if result builder transform was applied
1 parent 00eaed3 commit 4d1e44f

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

lib/Sema/TypeCheckStmt.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2587,18 +2587,22 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
25872587
func, builderType,
25882588
/*ClosuresInResultBuilderDontParticipateInInference=*/
25892589
ctx.CompletionCallback == nullptr && ctx.SolutionCallback == nullptr);
2590-
if (optBody && *optBody) {
2590+
if (ctx.CompletionCallback && ctx.CompletionCallback->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) {
25912598
// Wire up the function body now.
25922599
func->setBody(*optBody, AbstractFunctionDecl::BodyKind::TypeChecked);
25932600
return false;
25942601
}
2595-
// FIXME: We failed to apply the result builder transform. Fall back to
2596-
// just type checking the node that contains the code completion token.
2597-
// This may be missing some context from the result builder but in
2598-
// practice it often contains sufficient information to provide a decent
2599-
// level of code completion that's better than providing nothing at all.
2600-
// The proper solution would be to only partially type check the result
2601-
// builder so that this fall back would not be necessary.
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.
26022606
} else if (func->hasSingleExpressionBody() &&
26032607
func->getResultInterfaceType()->isVoid()) {
26042608
// The function returns void. We don't need an explicit return, no matter

test/IDE/complete_in_result_builder.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,3 +339,24 @@ func testSwitchInResultBuilder() {
339339
// SWITCH_IN_RESULT_BUILDER: Begin completions, 1 item
340340
// SWITCH_IN_RESULT_BUILDER-DAG: Decl[EnumElement]/CurrNominal/Flair[ExprSpecific]/TypeRelation[Convertible]: alertDismissed[#Action#];
341341
}
342+
343+
func testCompleteIfLetInResultBuilder() {
344+
func takeClosure(_ x: () -> Void) -> Int {
345+
return 0
346+
}
347+
348+
@resultBuilder struct MyResultBuilder {
349+
static func buildBlock() -> Int { return 0 }
350+
static func buildBlock(_ content: Int) -> Int { content }
351+
}
352+
353+
@MyResultBuilder func test(integer: Int?) -> Int {
354+
takeClosure {
355+
if let #^IF_LET_IN_RESULT_BUILDER^#integer = integer {
356+
}
357+
}
358+
// IF_LET_IN_RESULT_BUILDER: Begin completions, 1 items
359+
// IF_LET_IN_RESULT_BUILDER: Decl[LocalVar]/Local: integer[#Int?#]; name=integer
360+
// IF_LET_IN_RESULT_BUILDER: End completions
361+
}
362+
}

0 commit comments

Comments
 (0)