Skip to content

Commit c4b0983

Browse files
author
Nathan Hawes
committed
[Sema][CodeCompletion] Allow empty case statement bodies in the result builder transform...
..when typechecking for code completion. They were disallowed to give better diagnostics, but code completion suppresses diagnostics and can't provide any completions at all when the transform fails as it doesn't get any types. Resolves rdar://problem/74028722
1 parent 77d828d commit c4b0983

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)