mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Move out-of-place SingleValueStmtExpr checking into `performSyntacticExprDiagnostics`, to ensure we catch all expressions. Previously we did the walk as a part of Decl-based MiscDiagnostics, but it turns out that can miss expressions in property initializers, subscript default arguments, and custom attrs. This does mean that we'll now no longer diagnose out-of-place if/switch exprs if the expression didn't type-check, but that's consistent with the rest of MiscDiagnostics, and I don't think it will be a major issue in practice. We probably ought to consider moving this checking into PreCheckExpr, but that would require first separating out SequenceExpr folding, which has other consequences, and so I'm leaving as future work for now.
821 lines
17 KiB
Swift
821 lines
17 KiB
Swift
// RUN: %target-typecheck-verify-swift
|
|
|
|
enum E {
|
|
case e
|
|
case f
|
|
case g(Int)
|
|
}
|
|
|
|
func testDotSyntax1() -> E {
|
|
switch Bool.random() { case true: .e case false: .f }
|
|
}
|
|
func testDotSyntax2() -> E? {
|
|
switch Bool.random() { case true: .e case false: .f }
|
|
}
|
|
func testDotSyntax3() -> E? {
|
|
switch Bool.random() { case true: .e case false: .none }
|
|
}
|
|
func testDotSyntax4() -> Int {
|
|
let i = switch Bool.random() { case true: 0 case false: .random() }
|
|
// expected-error@-1 {{cannot infer contextual base in reference to member 'random'}}
|
|
|
|
return i
|
|
}
|
|
|
|
let testVar1: E = switch Bool.random() { case true: .e case false: .f }
|
|
let testVar2: E? = switch Bool.random() { case true: .e case false: .f }
|
|
let testVar3: E? = switch Bool.random() { case true: .e case false: .none }
|
|
let testVar4: E? = switch Bool.random() { case true: nil case false: .e }
|
|
|
|
let testVar5 = switch Bool.random() { case true: 0 case false: 1.0 }
|
|
// expected-error@-1 {{branches have mismatching types 'Int' and 'Double'}}
|
|
|
|
let testVar6: Double = switch Bool.random() { case true: 0 case false: 1.0 }
|
|
|
|
let testVar7: Double = switch 0 {
|
|
case 1: 0 + 1
|
|
case 2: 1.0 + 3
|
|
default: 9 + 0.0
|
|
}
|
|
|
|
let testContextualMismatch1: String = switch Bool.random() { case true: 1 case false: "" }
|
|
// expected-error@-1 {{cannot convert value of type 'Int' to specified type 'String'}}
|
|
|
|
let testContextualMismatch2: String = switch Bool.random() { case true: 1 case false: 2 }
|
|
// expected-error@-1 {{cannot convert value of type 'Int' to specified type 'String'}}
|
|
|
|
func proposalExample1(_ x: Int) -> Float {
|
|
let y = switch x {
|
|
case 0..<0x80: 1 // expected-error {{branches have mismatching types 'Int' and 'Double'}}
|
|
case 0x80..<0x0800: 2.0
|
|
case 0x0800..<0x1_0000: 3.0
|
|
default: 4.5
|
|
}
|
|
return y
|
|
}
|
|
|
|
func proposalExample2(_ x: Int) -> Float {
|
|
let y: Float = switch x {
|
|
case 0..<0x80: 1
|
|
case 0x80..<0x0800: 2.0
|
|
case 0x0800..<0x1_0000: 3.0
|
|
default: 4.5
|
|
}
|
|
return y
|
|
}
|
|
|
|
enum Node { case B, R }
|
|
|
|
enum Tree {
|
|
indirect case node(Node, Tree, Tree, Tree)
|
|
case leaf
|
|
|
|
func proposalExample3(_ z: Tree, d: Tree) -> Tree {
|
|
switch self {
|
|
case let .node(.B, .node(.R, .node(.R, a, x, b), y, c), z, d):
|
|
.node(.R, .node(.B,a,x,b),y,.node(.B,c,z,d))
|
|
case let .node(.B, .node(.R, a, x, .node(.R, b, y, c)), z, d):
|
|
.node(.R, .node(.B,a,x,b),y,.node(.B,c,z,d))
|
|
case let .node(.B, a, x, .node(.R, .node(.R, b, y, c), z, d)):
|
|
.node(.R, .node(.B,a,x,b),y,.node(.B,c,z,d))
|
|
case let .node(.B, a, x, .node(.R, b, y, .node(.R, c, z, d))):
|
|
.node(.R, .node(.B,a,x,b),y,.node(.B,c,z,d))
|
|
default:
|
|
self
|
|
}
|
|
}
|
|
}
|
|
|
|
enum F {
|
|
case a(Int)
|
|
}
|
|
|
|
func overloadedWithGenericAndInt<T>(_ x: T) -> T { x }
|
|
func overloadedWithGenericAndInt(_ x: Int) -> Int { x }
|
|
|
|
struct S {
|
|
var f: F
|
|
mutating func foo() -> Int {
|
|
switch f {
|
|
case .a(let x):
|
|
// Make sure we don't try and shrink, which would lead to trying to
|
|
// type-check the switch early.
|
|
overloadedWithGenericAndInt(x + x)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testSingleCaseReturn(_ f: F) -> Int {
|
|
switch f {
|
|
case .a(let i): i
|
|
}
|
|
}
|
|
|
|
func testSingleCaseReturnClosure(_ f: F) -> Int {
|
|
let fn = {
|
|
switch f {
|
|
case .a(let i): i
|
|
}
|
|
}
|
|
return fn()
|
|
}
|
|
|
|
func testWhereClause(_ f: F) -> Int {
|
|
switch f {
|
|
case let .a(x) where x.isMultiple(of: 2):
|
|
return 0
|
|
default:
|
|
return 1
|
|
}
|
|
}
|
|
|
|
func testNestedOptional() -> Int? {
|
|
switch Bool.random() {
|
|
case true:
|
|
1
|
|
case false:
|
|
if .random() {
|
|
1
|
|
} else {
|
|
nil
|
|
}
|
|
}
|
|
}
|
|
|
|
func testNestedOptionalSwitch() -> Int? {
|
|
switch Bool.random() {
|
|
case true:
|
|
1
|
|
case false:
|
|
switch Bool.random() {
|
|
case true:
|
|
1
|
|
case false:
|
|
nil
|
|
}
|
|
}
|
|
}
|
|
|
|
func testNestedOptionalMismatch1() -> Int? {
|
|
switch Bool.random() {
|
|
case true:
|
|
1
|
|
case false:
|
|
if .random() {
|
|
1
|
|
} else {
|
|
"" // expected-error {{cannot convert value of type 'String' to specified type 'Int'}}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
func testNestedOptionalMismatch2() -> Int {
|
|
switch Bool.random() {
|
|
case true:
|
|
1
|
|
case false:
|
|
if .random() {
|
|
1
|
|
} else {
|
|
// FIXME: Seems like we could do better here
|
|
nil // expected-error {{cannot convert value of type 'ExpressibleByNilLiteral' to specified type 'Int'}}
|
|
}
|
|
}
|
|
}
|
|
|
|
func testAssignment() {
|
|
var d: Double = switch Bool.random() { case true: 0 case false: 1.0 }
|
|
d = switch Bool.random() { case true: 0 case false: 1 }
|
|
_ = d
|
|
}
|
|
|
|
struct TestBadReturn {
|
|
var y = switch Bool.random() { case true: return case false: 0 } // expected-error {{return invalid outside of a func}}
|
|
}
|
|
|
|
func testNil1(_ x: Bool) {
|
|
let _ = switch x { case true: 42 case false: nil } // expected-error {{'nil' requires a contextual type}}
|
|
}
|
|
func testNil2(_ x: Bool) {
|
|
let _ = switch x { case true: nil case false: 42 } // expected-error {{'nil' requires a contextual type}}
|
|
}
|
|
|
|
func testNil3(_ x: Bool) {
|
|
// In this case, we allow propagating the type from the first branch into
|
|
// later branches.
|
|
let _: _? = switch x { case true: 42 case false: nil }
|
|
}
|
|
func testNil4(_ x: Bool) {
|
|
// FIXME: Bad diagnostic (#63130)
|
|
let _: _? = switch x { case true: nil case false: 42 } // expected-error {{type of expression is ambiguous without a type annotation}}
|
|
}
|
|
|
|
enum G<T> {
|
|
// expected-note@-1 {{arguments to generic parameter 'T' ('Double' and 'Int') are expected to be equal}}
|
|
// expected-note@-2 {{'T' declared as parameter to type 'G'}}
|
|
case x(T), y
|
|
}
|
|
|
|
func testUnboundGeneric1() -> G<Int> {
|
|
let x: G = switch Bool.random() { case true: .x(5) case false: .x(1) }
|
|
return x
|
|
}
|
|
|
|
func testUnboundGeneric2() -> G<Int> {
|
|
let x: G = switch Bool.random() { case true: .x(5) case false: .y }
|
|
return x
|
|
}
|
|
|
|
func testUnboundGeneric3() -> G<Int> {
|
|
let x: G = switch Bool.random() { case true: .y case false: .y }
|
|
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
|
|
return x
|
|
}
|
|
|
|
func testUnboundGeneric4() -> G<Int> {
|
|
let x: G = switch Bool.random() { case true: .x(5.0) case false: .x(5.0) }
|
|
return x
|
|
// expected-error@-1 {{cannot convert return expression of type 'G<Double>' to return type 'G<Int>'}}
|
|
}
|
|
|
|
func testUnboundGeneric5() -> G<Int> {
|
|
let x: G = switch Bool.random() { case true: .x(5) case false: .x(5.0) }
|
|
// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Int'}}
|
|
return x
|
|
}
|
|
|
|
func testNeverConversion1() -> Int {
|
|
switch Bool.random() {
|
|
case true:
|
|
1
|
|
case false:
|
|
fatalError()
|
|
}
|
|
}
|
|
|
|
func testNeverConversion2() -> Int {
|
|
return switch Bool.random() {
|
|
case true:
|
|
1
|
|
case false:
|
|
fatalError()
|
|
}
|
|
}
|
|
|
|
func testNeverConversion3() -> Int {
|
|
switch Bool.random() {
|
|
case true:
|
|
1
|
|
case false:
|
|
if .random() {
|
|
fatalError()
|
|
} else {
|
|
2
|
|
}
|
|
}
|
|
}
|
|
|
|
func testNeverConversion4() -> Int {
|
|
return switch Bool.random() {
|
|
case true:
|
|
1
|
|
case false:
|
|
if .random() {
|
|
fatalError()
|
|
} else {
|
|
2
|
|
}
|
|
}
|
|
}
|
|
|
|
func testNeverConversion5() -> Int {
|
|
{
|
|
switch Bool.random() {
|
|
case true:
|
|
1
|
|
case false:
|
|
if .random() {
|
|
fatalError()
|
|
} else {
|
|
2
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func testNeverConversion6(_ e: E) -> String {
|
|
switch e {
|
|
default:
|
|
fatalError()
|
|
}
|
|
}
|
|
|
|
func testVoidConversion() {
|
|
func foo(_ fn: () -> Void) {}
|
|
func bar<T>(_ fn: () -> T) {}
|
|
|
|
// Okay for an implicit return, including nested as this preserves source
|
|
// compatibility.
|
|
foo {
|
|
switch Bool.random() {
|
|
case true:
|
|
0 // expected-warning {{integer literal is unused}}
|
|
case false:
|
|
0 // expected-warning {{integer literal is unused}}
|
|
}
|
|
}
|
|
foo {
|
|
switch Bool.random() {
|
|
case true:
|
|
0 // expected-warning {{integer literal is unused}}
|
|
case false:
|
|
if .random() {
|
|
0 // expected-warning {{integer literal is unused}}
|
|
} else {
|
|
0 // expected-warning {{integer literal is unused}}
|
|
}
|
|
}
|
|
}
|
|
foo {
|
|
switch Bool.random() {
|
|
default:
|
|
0 // expected-warning {{integer literal is unused}}
|
|
}
|
|
}
|
|
bar {
|
|
switch Bool.random() {
|
|
case true:
|
|
0
|
|
case false:
|
|
0
|
|
}
|
|
}
|
|
bar {
|
|
switch Bool.random() {
|
|
case true:
|
|
0
|
|
case false:
|
|
if .random() {
|
|
0
|
|
} else {
|
|
0
|
|
}
|
|
}
|
|
}
|
|
bar {
|
|
switch Bool.random() {
|
|
case true:
|
|
()
|
|
case false:
|
|
0 // expected-warning {{integer literal is unused}}
|
|
}
|
|
}
|
|
bar {
|
|
switch Bool.random() {
|
|
case true:
|
|
0 // expected-warning {{integer literal is unused}}
|
|
case false:
|
|
if .random() {
|
|
()
|
|
} else {
|
|
0 // expected-warning {{integer literal is unused}}
|
|
}
|
|
}
|
|
}
|
|
// We allow the branches to mismatch to preserve source compatibility.
|
|
// (this example is silly, but this occurs in the wild for more innocuous
|
|
// things like branches that do set insertions and removals).
|
|
bar {
|
|
switch Bool.random() { case true: 0 case false: "" }
|
|
// expected-warning@-1 {{integer literal is unused}}
|
|
// expected-warning@-2 {{string literal is unused}}
|
|
}
|
|
bar {
|
|
switch Bool.random() {
|
|
case true:
|
|
switch Bool.random() {
|
|
case true:
|
|
0 // expected-warning {{integer literal is unused}}
|
|
case false:
|
|
[0] // expected-warning {{expression of type '[Int]' is unused}}
|
|
}
|
|
case false:
|
|
"" // expected-warning {{string literal is unused}}
|
|
}
|
|
}
|
|
bar { () -> Void in
|
|
switch Bool.random() { case true: 0 case false: "" }
|
|
// expected-warning@-1 {{integer literal is unused}}
|
|
// expected-warning@-2 {{string literal is unused}}
|
|
}
|
|
bar { () -> Void in
|
|
switch Bool.random() {
|
|
case true:
|
|
switch Bool.random() {
|
|
case true:
|
|
0 // expected-warning {{integer literal is unused}}
|
|
case false:
|
|
[0] // expected-warning {{expression of type '[Int]' is unused}}
|
|
}
|
|
case false:
|
|
"" // expected-warning {{string literal is unused}}
|
|
}
|
|
}
|
|
bar { () -> Int in
|
|
switch Bool.random() { case true: 0 case false: "" } // expected-error {{cannot convert value of type 'String' to specified type 'Int'}}
|
|
}
|
|
bar { () -> Int in
|
|
switch Bool.random() {
|
|
case true:
|
|
switch Bool.random() {
|
|
case true:
|
|
0
|
|
case false:
|
|
[0] // expected-error {{cannot convert value of type '[Int]' to specified type 'Int'}}
|
|
}
|
|
case false:
|
|
""
|
|
}
|
|
}
|
|
|
|
// Not okay for an explicit return.
|
|
foo {
|
|
return switch Bool.random() {
|
|
case true:
|
|
0 // expected-error {{cannot convert value of type 'Int' to specified type 'Void'}}
|
|
case false:
|
|
0
|
|
}
|
|
}
|
|
foo {
|
|
return switch Bool.random() {
|
|
case true:
|
|
0 // expected-error {{cannot convert value of type 'Int' to specified type 'Void'}}
|
|
case false:
|
|
if .random() {
|
|
0
|
|
} else {
|
|
0
|
|
}
|
|
}
|
|
}
|
|
bar {
|
|
return switch Bool.random() {
|
|
case true:
|
|
0
|
|
case false:
|
|
0
|
|
}
|
|
}
|
|
bar {
|
|
return switch Bool.random() {
|
|
case true:
|
|
0
|
|
case false:
|
|
if .random() {
|
|
0
|
|
} else {
|
|
0
|
|
}
|
|
}
|
|
}
|
|
bar {
|
|
return switch Bool.random() {
|
|
case true:
|
|
() // expected-error {{branches have mismatching types '()' and 'Int'}}
|
|
case false:
|
|
0
|
|
}
|
|
}
|
|
bar {
|
|
return switch Bool.random() {
|
|
case true:
|
|
0
|
|
case false:
|
|
if .random() {
|
|
() // expected-error {{branches have mismatching types '()' and 'Int'}}
|
|
} else {
|
|
0
|
|
}
|
|
}
|
|
}
|
|
bar {
|
|
return switch Bool.random() { case true: 0 case false: "" } // expected-error {{branches have mismatching types 'Int' and 'String'}}
|
|
}
|
|
bar {
|
|
return switch Bool.random() {
|
|
case true:
|
|
switch Bool.random() {
|
|
case true:
|
|
0 // expected-error {{branches have mismatching types 'Int' and '[Int]'}}
|
|
case false:
|
|
[0]
|
|
}
|
|
case false:
|
|
""
|
|
}
|
|
}
|
|
}
|
|
|
|
struct SomeError: Error {}
|
|
|
|
func testThrowInference() {
|
|
func notThrowing(_ fn: () -> Int) {}
|
|
notThrowing { // expected-error {{invalid conversion from throwing function of type '() throws -> Int' to non-throwing function type '() -> Int'}}
|
|
switch Bool.random() {
|
|
case true:
|
|
0
|
|
case false:
|
|
throw SomeError()
|
|
}
|
|
}
|
|
|
|
@discardableResult
|
|
func rethrowing<T>(_ fn: () throws -> T) rethrows -> T { try fn() }
|
|
rethrowing {
|
|
// expected-error@-1 {{call can throw, but it is not marked with 'try' and the error is not handled}}
|
|
// expected-note@-2 {{call is to 'rethrows' function, but argument function can throw}}
|
|
switch Bool.random() {
|
|
case true:
|
|
0
|
|
case false:
|
|
throw SomeError()
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: Pound if
|
|
|
|
func testPoundIf1() -> Int {
|
|
switch Bool.random() {
|
|
case true:
|
|
#if true
|
|
0
|
|
#else
|
|
""
|
|
#endif
|
|
case false:
|
|
0
|
|
}
|
|
}
|
|
|
|
func testPoundIf2() -> String {
|
|
switch Bool.random() {
|
|
case true:
|
|
#if true
|
|
0 // expected-error {{cannot convert value of type 'Int' to specified type 'String'}}
|
|
#else
|
|
""
|
|
#endif
|
|
case false:
|
|
""
|
|
}
|
|
}
|
|
|
|
func testPoundIf3() -> String {
|
|
switch Bool.random() {
|
|
case true:
|
|
#if false
|
|
0
|
|
#else
|
|
""
|
|
#endif
|
|
case false:
|
|
""
|
|
}
|
|
}
|
|
|
|
func testPoundIf4() -> String {
|
|
let x = switch Bool.random() {
|
|
case true:
|
|
#if true
|
|
0 // expected-error {{branches have mismatching types 'Int' and 'String'}}
|
|
#else
|
|
""
|
|
#endif
|
|
case false:
|
|
""
|
|
}
|
|
return x
|
|
}
|
|
|
|
func testPoundIf5() -> String {
|
|
let x = switch Bool.random() {
|
|
case true:
|
|
#if false
|
|
0
|
|
#else
|
|
""
|
|
#endif
|
|
case false:
|
|
""
|
|
}
|
|
return x
|
|
}
|
|
|
|
func testPoundIfClosure1() -> Int {
|
|
let fn = {
|
|
switch Bool.random() {
|
|
case true:
|
|
#if true
|
|
0
|
|
#else
|
|
""
|
|
#endif
|
|
case false:
|
|
0
|
|
}
|
|
}
|
|
return fn()
|
|
}
|
|
|
|
func testPoundIfClosure2() -> String {
|
|
let fn: () -> String = {
|
|
switch Bool.random() {
|
|
case true:
|
|
#if true
|
|
0 // expected-error {{cannot convert value of type 'Int' to specified type 'String'}}
|
|
#else
|
|
""
|
|
#endif
|
|
case false:
|
|
""
|
|
}
|
|
}
|
|
return fn()
|
|
}
|
|
|
|
// MARK: Subtyping
|
|
|
|
class A {}
|
|
class B : A {}
|
|
class C : A {}
|
|
|
|
func testSubtyping1() -> A {
|
|
// We can join to A.
|
|
let x = switch Bool.random() {
|
|
case true:
|
|
B()
|
|
case false:
|
|
C()
|
|
}
|
|
let y = .random() ? B() : C()
|
|
if .random() {
|
|
return x
|
|
} else {
|
|
return y
|
|
}
|
|
}
|
|
|
|
// MARK: Opaque result types
|
|
|
|
protocol P {}
|
|
extension P {
|
|
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
|
|
func foo() -> some P { 0 }
|
|
}
|
|
extension Int : P {}
|
|
extension Never : P {}
|
|
|
|
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
|
|
func testOpaqueReturn1() -> some P {
|
|
switch Bool.random() {
|
|
case true:
|
|
0
|
|
case false:
|
|
1
|
|
}
|
|
}
|
|
|
|
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
|
|
func testOpaqueReturn2() -> some P {
|
|
switch Bool.random() {
|
|
case true:
|
|
0
|
|
case false:
|
|
fatalError()
|
|
}
|
|
}
|
|
|
|
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
|
|
func testOpaqueReturn3(_ x: Int) -> some P {
|
|
switch Bool.random() {
|
|
case true:
|
|
return x.foo()
|
|
case false:
|
|
fatalError()
|
|
}
|
|
}
|
|
|
|
// MARK: Result builders
|
|
|
|
enum Either<T, U> {
|
|
case first(T), second(U)
|
|
}
|
|
|
|
@resultBuilder
|
|
struct Builder {
|
|
static func buildBlock<T>(_ x: T) -> T { x }
|
|
static func buildBlock<T, U>(_ x: T, _ y: U) -> (T, U) { (x, y) }
|
|
|
|
static func buildEither<T, U>(first x: T) -> Either<T, U> { .first(x) }
|
|
static func buildEither<T, U>(second x: U) -> Either<T, U> { .second(x) }
|
|
|
|
static func buildExpression(_ x: Double) -> Double { x }
|
|
static func buildExpression<T>(_ x: T) -> T { x }
|
|
}
|
|
|
|
@Builder
|
|
func singleExprBuilder() -> Either<String, Int> {
|
|
switch Bool.random() {
|
|
case true:
|
|
""
|
|
case false:
|
|
1
|
|
}
|
|
}
|
|
|
|
@Builder
|
|
func builderStaticMember() -> (Either<String, Int>, Double) {
|
|
switch Bool.random() {
|
|
case true:
|
|
""
|
|
case false:
|
|
1
|
|
}
|
|
.pi // This becomes a static member ref, not a member on an if expression.
|
|
}
|
|
|
|
@Builder
|
|
func builderNotPostfix() -> (Either<String, Int>, Bool) {
|
|
switch Bool.random() { case true: "" case false: 1 } !.random() // expected-error {{consecutive statements on a line must be separated by ';'}}
|
|
}
|
|
|
|
@Builder
|
|
func builderWithBinding() -> Either<String, Int> {
|
|
// Make sure the binding gets type-checked as a switch expression, but the
|
|
// other if block gets type-checked as a stmt.
|
|
let str = switch Bool.random() {
|
|
case true: "a"
|
|
case false: "b"
|
|
}
|
|
if .random() {
|
|
str
|
|
} else {
|
|
1
|
|
}
|
|
}
|
|
|
|
|
|
@Builder
|
|
func builderWithInvalidBinding() -> Either<String, Int> {
|
|
let str = (switch Bool.random() { default: "a" })
|
|
// expected-error@-1 {{'switch' may only be used as expression in return, throw, or as the source of an assignment}}
|
|
if .random() {
|
|
str
|
|
} else {
|
|
1
|
|
}
|
|
}
|
|
|
|
func takesBuilder(@Builder _ fn: () -> Either<String, Int>) {}
|
|
|
|
func builderClosureWithBinding() {
|
|
takesBuilder {
|
|
// Make sure the binding gets type-checked as a switch expression, but the
|
|
// other if block gets type-checked as a stmt.
|
|
let str = switch Bool.random() { case true: "a" case false: "b" }
|
|
switch Bool.random() {
|
|
case true:
|
|
str
|
|
case false:
|
|
1
|
|
}
|
|
}
|
|
}
|
|
|
|
func builderClosureWithInvalidBinding() {
|
|
takesBuilder {
|
|
let str = (switch Bool.random() { case true: "a" case false: "b" })
|
|
// expected-error@-1 {{'switch' may only be used as expression in return, throw, or as the source of an assignment}}
|
|
switch Bool.random() {
|
|
case true:
|
|
str
|
|
case false:
|
|
1
|
|
}
|
|
}
|
|
}
|
|
|
|
func builderInClosure() {
|
|
takesBuilder {
|
|
switch Bool.random() {
|
|
case true:
|
|
""
|
|
case false:
|
|
1
|
|
}
|
|
}
|
|
}
|