Skip to content

Commit d3f624f

Browse files
author
Nathan Hawes
authored
Merge pull request #36013 from nathawes/fix-missing-completions-in-invalid-result-builder
[Sema][CodeCompletion] Allow empty case statement bodies in the result builder transform...
2 parents 9c6c9a5 + c4b0983 commit d3f624f

File tree

2 files changed

+67
-2
lines changed

2 files changed

+67
-2
lines changed

lib/Sema/BuilderTransform.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -754,8 +754,13 @@ class BuilderClosureVisitor
754754
// statements by excluding invalid cases.
755755
if (auto *BS = dyn_cast<BraceStmt>(body)) {
756756
if (BS->getNumElements() == 0) {
757-
hadError = true;
758-
return nullptr;
757+
// HACK: still allow empty bodies if typechecking for code
758+
// completion. Code completion ignores diagnostics
759+
// and won't get any types if we fail.
760+
if (!ctx.SourceMgr.hasCodeCompletionBuffer()) {
761+
hadError = true;
762+
return nullptr;
763+
}
759764
}
760765
}
761766

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t
2+
3+
enum Either<T,U> { case first(T), second(U) }
4+
indirect enum ResultBuilderTerm<Expression> {
5+
case expression(Expression)
6+
case block([ResultBuilderTerm])
7+
case either(Either<ResultBuilderTerm, ResultBuilderTerm>)
8+
}
9+
10+
protocol ResultBuilder {
11+
associatedtype Expression
12+
typealias Component = ResultBuilderTerm<Expression>
13+
associatedtype FinalResult
14+
15+
static func buildFinalResult(_ component: Component) -> FinalResult
16+
}
17+
18+
extension ResultBuilder {
19+
static func buildExpression(_ expression: Expression) -> Component { .expression(expression) }
20+
static func buildBlock(_ components: Component...) -> Component { .block(components) }
21+
static func buildEither(first: Component) -> Component { .either(.first(first)) }
22+
static func buildEither(second: Component) -> Component { .either(.second(second)) }
23+
24+
}
25+
26+
@resultBuilder
27+
enum ArrayBuilder<E>: ResultBuilder {
28+
typealias Expression = E
29+
typealias FinalResult = [E]
30+
31+
static func buildFinalResult(_ component: Component) -> FinalResult {
32+
switch component {
33+
case .expression(let e): return [e]
34+
case .block(let children): return children.flatMap(buildFinalResult)
35+
case .either(.first(let child)): return buildFinalResult(child)
36+
case .either(.second(let child)): return buildFinalResult(child)
37+
}
38+
}
39+
}
40+
41+
func test(@ArrayBuilder<Int> a: () -> [Int]) {}
42+
enum MyEnum { case a, b }
43+
44+
test {
45+
switch MyEnum.a {
46+
case .#^EMPTYCASE?check=MYENUM_MEMBERS^#
47+
}
48+
}
49+
50+
test {
51+
switch MyEnum.a {
52+
case .a:
53+
case .#^SECONDEMPTYCASE?check=MYENUM_MEMBERS^#
54+
}
55+
}
56+
57+
// MYENUM_MEMBERS: Begin completions
58+
// MYENUM_MEMBERS-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: a[#MyEnum#]; name=a
59+
// MYENUM_MEMBERS-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: b[#MyEnum#]; name=b
60+
// MYENUM_MEMBERS: End completions

0 commit comments

Comments
 (0)