Skip to content

Commit f7753de

Browse files
committed
[Completion] Only skip result builder expressions in the same builder
Previously we would skip any expression in a result builder that didn't contain the completion token, but that would cause issues if e.g the result builder was needed to infer the type of a variable that we're completing on. Instead, only skip expressions in a result builder if the completion token is in the same builder and the expression itself doesn't contain the completion. rdar://127154780
1 parent c8b5344 commit f7753de

File tree

2 files changed

+48
-6
lines changed

2 files changed

+48
-6
lines changed

lib/Sema/BuilderTransform.cpp

+12-6
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ class ResultBuilderTransform
7272
DeclContext *dc;
7373
ResultBuilder builder;
7474

75+
/// The source range of the body.
76+
SourceRange bodyRange;
77+
7578
/// The result type of this result builder body.
7679
Type ResultType;
7780

@@ -80,9 +83,9 @@ class ResultBuilderTransform
8083

8184
public:
8285
ResultBuilderTransform(ConstraintSystem &cs, DeclContext *dc,
83-
Type builderType, Type resultTy)
86+
SourceRange bodyRange, Type builderType, Type resultTy)
8487
: ctx(cs.getASTContext()), dc(dc), builder(cs, dc, builderType),
85-
ResultType(resultTy) {}
88+
bodyRange(bodyRange), ResultType(resultTy) {}
8689

8790
UnsupportedElt getUnsupportedElement() const { return FirstUnsupported; }
8891

@@ -238,12 +241,14 @@ class ResultBuilderTransform
238241
// buildBlock higher.
239242
buildBlockArguments.push_back(expr);
240243
} else if (ctx.CompletionCallback && expr->getSourceRange().isValid() &&
244+
containsIDEInspectionTarget(bodyRange, ctx.SourceMgr) &&
241245
!containsIDEInspectionTarget(expr->getSourceRange(),
242246
ctx.SourceMgr)) {
243-
// A statement that doesn't contain the code completion expression can't
244-
// influence the type of the code completion expression. Add a variable
245-
// for it that we can put into the buildBlock call but don't add the
246-
// expression itself into the transformed body to improve performance.
247+
// A top-level expression that doesn't contain the code completion
248+
// expression can't influence the type of the code completion expression
249+
// if they're in the same result builder. Add a variable for it that we
250+
// can put into the buildBlock call but don't add the expression itself
251+
// into the transformed body to improve performance.
247252
auto *resultVar = buildPlaceholderVar(expr->getStartLoc(), newBody);
248253
buildBlockArguments.push_back(
249254
builder.buildVarRef(resultVar, expr->getStartLoc()));
@@ -1176,6 +1181,7 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
11761181
// let's do it and cache the result.
11771182
if (!transformedBody) {
11781183
ResultBuilderTransform transform(*this, fn.getAsDeclContext(),
1184+
fn.getBody()->getSourceRange(),
11791185
builderType, bodyResultType);
11801186
auto *body = transform.apply(fn.getBody());
11811187

test/IDE/complete_rdar127154780.swift

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t
3+
4+
// rdar://127154780 - Make sure we provide completions on variables that rely
5+
// on result builders being solved.
6+
7+
@resultBuilder
8+
enum Builder {
9+
static func buildBlock<T>(_ x: T) -> T { x }
10+
}
11+
12+
struct S {}
13+
14+
struct R<T> {
15+
init(@Builder _: () -> T) {}
16+
}
17+
18+
extension R where T == S {
19+
func bar() {}
20+
}
21+
22+
func foo() {
23+
let r = R() {
24+
S()
25+
}
26+
r.#^COMPLETE1?check=COMPLETE^#
27+
28+
let fn = {
29+
let r = R() {
30+
S()
31+
}
32+
r.#^COMPLETE2?check=COMPLETE^#
33+
}
34+
}
35+
// COMPLETE-DAG: Keyword[self]/CurrNominal: self[#R<S>#]; name=self
36+
// COMPLETE-DAG: Decl[InstanceMethod]/CurrNominal: bar()[#Void#]; name=bar()

0 commit comments

Comments
 (0)