blob: 74bdb5d27d4bd22b590b1e4952187c0d64c72fe5 [file] [log] [blame]
// RUN: %target-swift-emit-silgen -module-name switch %s | %FileCheck %s
func markUsed<T>(_ t: T) {}
// TODO: Implement tuple equality in the library.
// BLOCKED: <rdar://problem/13822406>
func ~= (x: (Int, Int), y: (Int, Int)) -> Bool {
return x.0 == y.0 && x.1 == y.1
}
// Some fake predicates for pattern guards.
func runced() -> Bool { return true }
func funged() -> Bool { return true }
func ansed() -> Bool { return true }
func foo() -> Int { return 0 }
func bar() -> Int { return 0 }
func foobar() -> (Int, Int) { return (0, 0) }
func a() {}
func b() {}
func c() {}
func d() {}
func e() {}
func f() {}
func g() {}
// CHECK-LABEL: sil hidden [ossa] @$s6switch5test1yyF
func test1() {
switch foo() {
// CHECK: function_ref @$s6switch3fooSiyF
case _:
// CHECK: function_ref @$s6switch1ayyF
a()
}
// CHECK: function_ref @$s6switch1byyF
b()
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch5test2yyF
func test2() {
switch foo() {
// CHECK: function_ref @$s6switch3fooSiyF
case _:
// CHECK: function_ref @$s6switch1ayyF
// CHECK: br [[CONT:bb[0-9]+]]
a()
case _: // The second case is unreachable.
b()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @$s6switch1cyyF
c()
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch5test3yyF
func test3() {
switch foo() {
// CHECK: function_ref @$s6switch3fooSiyF
// CHECK: function_ref @$s6switch6runcedSbyF
// CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[CASE2:bb[0-9]+]]
case _ where runced():
// CHECK: [[CASE1]]:
// CHECK: function_ref @$s6switch1ayyF
// CHECK: br [[CONT:bb[0-9]+]]
a()
case _:
// CHECK: [[CASE2]]:
// CHECK: function_ref @$s6switch1byyF
// CHECK: br [[CONT]]
b()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @$s6switch1cyyF
c()
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch5test4yyF
func test4() {
switch (foo(), bar()) {
// CHECK: function_ref @$s6switch3fooSiyF
// CHECK: function_ref @$s6switch3barSiyF
case _:
// CHECK: function_ref @$s6switch1ayyF
a()
}
// CHECK: function_ref @$s6switch1byyF
b()
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch5test5yyF
func test5() {
switch (foo(), bar()) {
// CHECK: function_ref @$s6switch3fooSiyF
// CHECK: function_ref @$s6switch3barSiyF
// CHECK: function_ref @$s6switch6runcedSbyF
// CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
case _ where runced():
// CHECK: [[CASE1]]:
// CHECK: function_ref @$s6switch1ayyF
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[NOT_CASE1]]:
// CHECK: function_ref @$s6switch6fungedSbyF
// CHECK: cond_br {{%.*}}, [[YES_CASE2:bb[0-9]+]], [[NOT_CASE2:bb[0-9]+]]
// CHECK: [[YES_CASE2]]:
case (_, _) where funged():
// CHECK: function_ref @$s6switch1byyF
// CHECK: br [[CONT]]
b()
case _:
// CHECK: [[NOT_CASE2]]:
// CHECK: function_ref @$s6switch1cyyF
c()
}
// CHECK: function_ref @$s6switch1dyyF
d()
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch5test6yyF
func test6() {
switch (foo(), bar()) {
// CHECK: function_ref @$s6switch3fooSiyF
// CHECK: function_ref @$s6switch3barSiyF
case (_, _):
// CHECK: function_ref @$s6switch1ayyF
// CHECK: br [[CONT:bb[0-9]+]]
a()
case (_, _): // The second case is unreachable.
b()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @$s6switch1cyyF
c()
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch5test7yyF
func test7() {
switch (foo(), bar()) {
// CHECK: function_ref @$s6switch3fooSiyF
// CHECK: function_ref @$s6switch3barSiyF
// CHECK: function_ref @$s6switch6runcedSbyF
// CHECK: cond_br {{%.*}}, [[YES_CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
// CHECK: [[YES_CASE1]]:
case (_, _) where runced():
// CHECK: function_ref @$s6switch1ayyF
// CHECK: br [[CONT:bb[0-9]+]]
a()
case (_, _):
// CHECK: [[NOT_CASE1]]:
// CHECK: function_ref @$s6switch1byyF
b()
}
c()
// CHECK: function_ref @$s6switch1cyyF
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch5test8yyF
func test8() {
switch (foo(), bar()) {
// CHECK: function_ref @$s6switch3fooSiyF
// CHECK: function_ref @$s6switch3barSiyF
// CHECK: function_ref @$s6switch6foobarSi_SityF
// CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
case foobar():
// CHECK: [[CASE1]]:
// CHECK: function_ref @$s6switch1ayyF
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[NOT_CASE1]]:
// CHECK: function_ref @$s6switch3fooSiyF
// CHECK: cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NOT_CASE2:bb[0-9]+]]
case (foo(), _):
// CHECK: [[CASE2]]:
// CHECK: function_ref @$s6switch1byyF
// CHECK: br [[CONT]]
b()
// CHECK: [[NOT_CASE2]]:
// CHECK: function_ref @$s6switch3barSiyF
// CHECK: cond_br {{%.*}}, [[CASE3_GUARD:bb[0-9]+]], [[NOT_CASE3:bb[0-9]+]]
// CHECK: [[CASE3_GUARD]]:
// CHECK: function_ref @$s6switch6runcedSbyF
// CHECK: cond_br {{%.*}}, [[CASE3:bb[0-9]+]], [[NOT_CASE3_GUARD:bb[0-9]+]]
case (_, bar()) where runced():
// CHECK: [[CASE3]]:
// CHECK: function_ref @$s6switch1cyyF
// CHECK: br [[CONT]]
c()
// CHECK: [[NOT_CASE3_GUARD]]:
// CHECK: [[NOT_CASE3]]:
// CHECK: function_ref @$s6switch3fooSiyF
// CHECK: cond_br {{%.*}}, [[CASE4_GUARD_1:bb[0-9]+]], [[NOT_CASE4_1:bb[0-9]+]]
// CHECK: [[CASE4_GUARD_1]]:
// CHECK: function_ref @$s6switch3barSiyF
// CHECK: cond_br {{%.*}}, [[CASE4_GUARD_2:bb[0-9]+]], [[NOT_CASE4_2:bb[0-9]+]]
// CHECK: [[CASE4_GUARD_2]]:
// CHECK: function_ref @$s6switch6fungedSbyF
// CHECK: cond_br {{%.*}}, [[CASE4:bb[0-9]+]], [[NOT_CASE4_3:bb[0-9]+]]
case (foo(), bar()) where funged():
// CHECK: [[CASE4]]:
// CHECK: function_ref @$s6switch1dyyF
// CHECK: br [[CONT]]
d()
// CHECK: [[NOT_CASE4_3]]:
// CHECK: [[NOT_CASE4_2]]:
// CHECK: [[NOT_CASE4_1]]:
// CHECK: function_ref @$s6switch3fooSiyF
// CHECK: cond_br {{%.*}}, [[CASE5_GUARD_1:bb[0-9]+]], [[NOT_CASE5:bb[0-9]+]]
// CHECK: [[CASE5_GUARD_1]]:
// CHECK: function_ref @$s6switch3barSiyF
// CHECK: cond_br {{%.*}}, [[YES_CASE5:bb[0-9]+]], [[NOT_CASE5:bb[0-9]+]]
// CHECK: [[YES_CASE5]]:
case (foo(), bar()):
// CHECK: function_ref @$s6switch1eyyF
// CHECK: br [[CONT]]
e()
// CHECK: [[NOT_CASE5]]:
// CHECK: br [[CASE6:bb[0-9]+]]
case _:
// CHECK: [[CASE6]]:
// CHECK: function_ref @$s6switch1fyyF
// CHECK: br [[CONT]]
f()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @$s6switch1gyyF
g()
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch5test9yyF
func test9() {
switch (foo(), bar()) {
// CHECK: function_ref @$s6switch3fooSiyF
// CHECK: function_ref @$s6switch3barSiyF
// CHECK: function_ref @$s6switch3fooSiyF
// CHECK: cond_br {{%.*}}, [[YES_CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
// CHECK: [[YES_CASE1]]:
case (foo(), _):
// CHECK: function_ref @$s6switch1ayyF
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[NOT_CASE1]]:
// CHECK: function_ref @$s6switch6foobarSi_SityF
// CHECK: cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NOT_CASE2:bb[0-9]+]]
case foobar():
// CHECK: [[CASE2]]:
// CHECK: function_ref @$s6switch1byyF
// CHECK: br [[CONT]]
b()
case _:
// CHECK: [[NOT_CASE2]]:
// CHECK: function_ref @$s6switch1cyyF
c()
}
// CHECK: function_ref @$s6switch1dyyF
d()
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch6test10yyF
func test10() {
switch (foo(), bar()) {
// CHECK: function_ref @$s6switch3fooSiyF
// CHECK: function_ref @$s6switch3barSiyF
// CHECK: cond_br {{%.*}}, [[YES_CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
// CHECK: [[YES_CASE1]]:
case (foo()...bar(), _):
// CHECK: function_ref @$s6switch1ayyF
// CHECK: br [[CONT:bb[0-9]+]]
a()
case _:
// CHECK: [[NOT_CASE1]]:
// CHECK: function_ref @$s6switch1byyF
// CHECK: br [[CONT]]
b()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @$s6switch1cyyF
c()
}
protocol P { func p() }
struct X : P { func p() {} }
struct Y : P { func p() {} }
struct Z : P { func p() {} }
// CHECK-LABEL: sil hidden [ossa] @$s6switch10test_isa_11pyAA1P_p_tF
func test_isa_1(p: P) {
// CHECK: [[PTMPBUF:%[0-9]+]] = alloc_stack $P
// CHECK-NEXT: copy_addr %0 to [initialization] [[PTMPBUF]] : $*P
switch p {
// CHECK: [[TMPBUF:%[0-9]+]] = alloc_stack $X
// CHECK: checked_cast_addr_br copy_on_success P in [[P:%.*]] : $*P to X in [[TMPBUF]] : $*X, [[IS_X:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]]
case is X:
// CHECK: [[IS_X]]:
// CHECK-NEXT: load [trivial] [[TMPBUF]]
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[FUNC:%.*]] = function_ref @$s6switch1ayyF
// CHECK-NEXT: apply [[FUNC]]()
// CHECK-NEXT: dealloc_stack [[TMPBUF]]
// CHECK-NEXT: destroy_addr [[PTMPBUF]]
// CHECK-NEXT: dealloc_stack [[PTMPBUF]]
a()
// CHECK: br [[CONT:bb[0-9]+]]
// CHECK: [[IS_NOT_X]]:
// CHECK: checked_cast_addr_br copy_on_success P in [[P]] : $*P to Y in {{%.*}} : $*Y, [[IS_Y:bb[0-9]+]], [[IS_NOT_Y:bb[0-9]+]]
// CHECK: [[IS_Y]]:
case is Y:
// CHECK: function_ref @$s6switch1byyF
// CHECK: br [[Y_CONT:bb[0-9]+]]
b()
// CHECK: [[IS_NOT_Y]]:
// CHECK: checked_cast_addr_br copy_on_success P in [[P]] : $*P to Z in {{%.*}} : $*Z, [[IS_Z:bb[0-9]+]], [[IS_NOT_Z:bb[0-9]+]]
// CHECK: [[IS_Z]]:
case is Z:
// CHECK: function_ref @$s6switch1cyyF
// CHECK: br [[Z_CONT:bb[0-9]+]]
c()
// CHECK: [[IS_NOT_Z]]:
case _:
// CHECK: function_ref @$s6switch1dyyF
// CHECK: br [[CONT]]
d()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @$s6switch1eyyF
e()
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch10test_isa_21pyAA1P_p_tF
func test_isa_2(p: P) {
switch (p, foo()) {
// CHECK: checked_cast_addr_br copy_on_success P in [[P:%.*]] : $*P to X in {{%.*}} : $*X, [[IS_X:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]]
// CHECK: [[IS_X]]:
// CHECK: function_ref @$s6switch3fooSiyF
// CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
case (is X, foo()):
// CHECK: [[CASE1]]:
// CHECK: function_ref @$s6switch1ayyF
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[IS_NOT_X]]:
// CHECK: checked_cast_addr_br copy_on_success P in [[P]] : $*P to Y in {{%.*}} : $*Y, [[IS_Y:bb[0-9]+]], [[IS_NOT_Y:bb[0-9]+]]
// CHECK: [[IS_Y]]:
// CHECK: function_ref @$s6switch3fooSiyF
// CHECK: cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NOT_CASE2:bb[0-9]+]]
case (is Y, foo()):
// CHECK: [[CASE2]]:
// CHECK: function_ref @$s6switch1byyF
// CHECK: br [[CONT]]
b()
// CHECK: [[NOT_CASE2]]:
// CHECK: [[IS_NOT_Y]]:
// CHECK: checked_cast_addr_br copy_on_success P in [[P:%.*]] : $*P to X in {{%.*}} : $*X, [[CASE3:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]]
case (is X, _):
// CHECK: [[CASE3]]:
// CHECK: function_ref @$s6switch1cyyF
// CHECK: br [[CONT]]
c()
// -- case (is Y, foo()):
// CHECK: [[IS_NOT_X]]:
// CHECK: checked_cast_addr_br copy_on_success P in [[P]] : $*P to Y in {{%.*}} : $*Y, [[IS_Y:bb[0-9]+]], [[IS_NOT_Y:bb[0-9]+]]
// CHECK: [[IS_Y]]:
// CHECK: function_ref @$s6switch3barSiyF
// CHECK: cond_br {{%.*}}, [[CASE4:bb[0-9]+]], [[NOT_CASE4:bb[0-9]+]]
case (is Y, bar()):
// CHECK: [[CASE4]]:
// CHECK: function_ref @$s6switch1dyyF
// CHECK: br [[CONT]]
d()
// CHECK: [[NOT_CASE4]]:
// CHECK: br [[CASE5:bb[0-9]+]]
// CHECK: [[IS_NOT_Y]]:
// CHECK: br [[CASE5]]
case _:
// CHECK: [[CASE5]]:
// CHECK: function_ref @$s6switch1eyyF
// CHECK: br [[CONT]]
e()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @$s6switch1fyyF
f()
}
class B {}
class C : B {}
class D1 : C {}
class D2 : D1 {}
class E : C {}
// CHECK-LABEL: sil hidden [ossa] @$s6switch16test_isa_class_11xyAA1BC_tF : $@convention(thin) (@guaranteed B) -> () {
func test_isa_class_1(x: B) {
// CHECK: bb0([[X:%.*]] : @guaranteed $B):
// CHECK: checked_cast_br [[X]] : $B to $D1, [[IS_D1:bb[0-9]+]], [[IS_NOT_D1:bb[0-9]+]]
switch x {
// CHECK: [[IS_D1]]([[CAST_D1:%.*]] : @guaranteed $D1):
// CHECK: [[CAST_D1_COPY:%.*]] = copy_value [[CAST_D1]]
// CHECK: function_ref @$s6switch6runcedSbyF : $@convention(thin) () -> Bool
// CHECK: cond_br {{%.*}}, [[YES_CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]]
// CHECK: [[YES_CASE1]]:
case is D1 where runced():
// CHECK: function_ref @$s6switch1ayyF
// CHECK: destroy_value [[CAST_D1_COPY]]
// CHECK: end_borrow [[CAST_D1]]
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[NO_CASE1]]:
// CHECK-NEXT: destroy_value [[CAST_D1_COPY]]
// CHECK-NEXT: end_borrow [[CAST_D1]]
// CHECK: br [[NEXT_CASE:bb[0-9]+]]
// CHECK: [[IS_NOT_D1]]([[CASTFAIL_D1:%.*]] : @guaranteed $B):
// CHECK-NEXT: end_borrow [[CASTFAIL_D1]]
// CHECK-NEXT: br [[NEXT_CASE]]
// CHECK: [[NEXT_CASE]]:
// CHECK: checked_cast_br [[X]] : $B to $D2, [[IS_D2:bb[0-9]+]], [[IS_NOT_D2:bb[0-9]+]]
case is D2:
// CHECK: [[IS_D2]]([[CAST_D2:%.*]] : @guaranteed $D2):
// CHECK: [[CAST_D2_COPY:%.*]] = copy_value [[CAST_D2]]
// CHECK: function_ref @$s6switch1byyF
// CHECK: destroy_value [[CAST_D2_COPY]]
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_NOT_D2]]([[CASTFAIL_D2:%.*]] : @guaranteed $B):
// CHECK: end_borrow [[CASTFAIL_D2]]
// CHECK: checked_cast_br [[X]] : $B to $E, [[IS_E:bb[0-9]+]], [[IS_NOT_E:bb[0-9]+]]
case is E where funged():
// CHECK: [[IS_E]]([[CAST_E:%.*]] : @guaranteed $E):
// CHECK: [[CAST_E_COPY:%.*]] = copy_value [[CAST_E]]
// CHECK: function_ref @$s6switch6fungedSbyF
// CHECK: cond_br {{%.*}}, [[CASE3:bb[0-9]+]], [[NO_CASE3:bb[0-9]+]]
// CHECK: [[CASE3]]:
// CHECK: function_ref @$s6switch1cyyF
// CHECK: destroy_value [[CAST_E_COPY]]
// CHECK: br [[CONT]]
c()
// CHECK: [[NO_CASE3]]:
// CHECK-NEXT: destroy_value [[CAST_E_COPY]]
// CHECK-NEXT: end_borrow
// CHECK: br [[NEXT_CASE:bb[0-9]+]]
// CHECK: [[IS_NOT_E]]([[NOTCAST_E:%.*]] : @guaranteed $B):
// CHECK: end_borrow [[NOTCAST_E]]
// CHECK: br [[NEXT_CASE]]
// CHECK: [[NEXT_CASE]]:
// CHECK: checked_cast_br [[X]] : $B to $C, [[IS_C:bb[0-9]+]], [[IS_NOT_C:bb[0-9]+]]
case is C:
// CHECK: [[IS_C]]([[CAST_C:%.*]] : @guaranteed $C):
// CHECK: [[CAST_C_COPY:%.*]] = copy_value [[CAST_C]]
// CHECK: function_ref @$s6switch1dyyF
// CHECK-NEXT: apply
// CHECK: destroy_value [[CAST_C_COPY]]
// CHECK: end_borrow [[CAST_C]]
// CHECK: br [[CONT]]
d()
// CHECK: [[IS_NOT_C]]([[NOCAST_C:%.*]] : @guaranteed $B):
// CHECK: end_borrow [[NOCAST_C]]
default:
// CHECK: function_ref @$s6switch1eyyF
// CHECK: br [[CONT]]
e()
}
// CHECK: [[CONT]]:
// CHECK: [[F_FUNC:%.*]] = function_ref @$s6switch1fyyF : $@convention(thin) () -> ()
// CHECK: apply [[F_FUNC]]()
f()
}
// CHECK: } // end sil function '$s6switch16test_isa_class_11xyAA1BC_tF'
// CHECK-LABEL: sil hidden [ossa] @$s6switch16test_isa_class_21xyXlAA1BC_tF : $@convention(thin)
func test_isa_class_2(x: B) -> AnyObject {
// CHECK: bb0([[X:%.*]] : @guaranteed $B):
switch x {
// CHECK: checked_cast_br [[X]] : $B to $D1, [[IS_D1:bb[0-9]+]], [[IS_NOT_D1:bb[0-9]+]]
case let y as D1 where runced():
// CHECK: [[IS_D1]]([[CAST_D1:%.*]] : @guaranteed $D1):
// CHECK: [[CAST_D1_COPY:%.*]] = copy_value [[CAST_D1]]
// CHECK: function_ref @$s6switch6runcedSbyF
// CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]]
// CHECK: [[CASE1]]:
// CHECK: function_ref @$s6switch1ayyF
// CHECK: [[BORROWED_CAST_D1_COPY:%.*]] = begin_borrow [[CAST_D1_COPY]]
// CHECK: [[CAST_D1_COPY_COPY:%.*]] = copy_value [[BORROWED_CAST_D1_COPY]]
// CHECK: [[RET:%.*]] = init_existential_ref [[CAST_D1_COPY_COPY]]
// CHECK: end_borrow [[BORROWED_CAST_D1_COPY]]
// CHECK: destroy_value [[CAST_D1_COPY]]
// CHECK: br [[CONT:bb[0-9]+]]([[RET]] : $AnyObject)
a()
return y
// CHECK: [[NO_CASE1]]:
// CHECK: destroy_value [[CAST_D1_COPY]]
// CHECK: br [[NEXT_CASE:bb5]]
// CHECK: [[IS_NOT_D1]]([[NOCAST_D1:%.*]] : @guaranteed $B):
// CHECK: end_borrow [[NOCAST_D1]]
// CHECK: br [[NEXT_CASE]]
// CHECK: [[NEXT_CASE]]:
// CHECK: checked_cast_br [[X]] : $B to $D2, [[CASE2:bb[0-9]+]], [[IS_NOT_D2:bb[0-9]+]]
case let y as D2:
// CHECK: [[CASE2]]([[CAST_D2:%.*]] : @guaranteed $D2):
// CHECK: [[CAST_D2_COPY:%.*]] = copy_value [[CAST_D2]]
// CHECK: function_ref @$s6switch1byyF
// CHECK: [[BORROWED_CAST_D2_COPY:%.*]] = begin_borrow [[CAST_D2_COPY]]
// CHECK: [[CAST_D2_COPY_COPY:%.*]] = copy_value [[BORROWED_CAST_D2_COPY]]
// CHECK: [[RET:%.*]] = init_existential_ref [[CAST_D2_COPY_COPY]]
// CHECK: end_borrow [[BORROWED_CAST_D2_COPY]]
// CHECK: destroy_value [[CAST_D2_COPY]]
// CHECK: br [[CONT]]([[RET]] : $AnyObject)
b()
return y
// CHECK: [[IS_NOT_D2]]([[NOCAST_D2:%.*]] : @guaranteed $B):
// CHECK: end_borrow [[NOCAST_D2]]
// CHECK: checked_cast_br [[X]] : $B to $E, [[IS_E:bb[0-9]+]], [[IS_NOT_E:bb[0-9]+]]
case let y as E where funged():
// CHECK: [[IS_E]]([[CAST_E:%.*]] : @guaranteed $E):
// CHECK: [[CAST_E_COPY:%.*]] = copy_value [[CAST_E]]
// CHECK: function_ref @$s6switch6fungedSbyF
// CHECK: cond_br {{%.*}}, [[CASE3:bb[0-9]+]], [[NO_CASE3:bb[0-9]+]]
// CHECK: [[CASE3]]:
// CHECK: function_ref @$s6switch1cyyF
// CHECK: [[BORROWED_CAST_E_COPY:%.*]] = begin_borrow [[CAST_E_COPY]]
// CHECK: [[CAST_E_COPY_COPY:%.*]] = copy_value [[BORROWED_CAST_E_COPY]]
// CHECK: [[RET:%.*]] = init_existential_ref [[CAST_E_COPY_COPY]]
// CHECK: end_borrow [[BORROWED_CAST_E_COPY]]
// CHECK: destroy_value [[CAST_E_COPY]]
// CHECK: end_borrow [[CAST_E]]
// CHECK: br [[CONT]]([[RET]] : $AnyObject)
c()
return y
// CHECK: [[NO_CASE3]]:
// CHECK destroy_value [[CAST_E_COPY]]
// CHECK: br [[NEXT_CASE:bb[0-9]+]]
// CHECK: [[IS_NOT_E]]([[NOCAST_E:%.*]] : @guaranteed $B):
// CHECK: end_borrow [[NOCAST_E]]
// CHECK: br [[NEXT_CASE]]
// CHECK: [[NEXT_CASE]]
// CHECK: checked_cast_br [[X]] : $B to $C, [[CASE4:bb[0-9]+]], [[IS_NOT_C:bb[0-9]+]]
case let y as C:
// CHECK: [[CASE4]]([[CAST_C:%.*]] : @guaranteed $C):
// CHECK: [[CAST_C_COPY:%.*]] = copy_value [[CAST_C]]
// CHECK: function_ref @$s6switch1dyyF
// CHECK: [[BORROWED_CAST_C_COPY:%.*]] = begin_borrow [[CAST_C_COPY]]
// CHECK: [[CAST_C_COPY_COPY:%.*]] = copy_value [[BORROWED_CAST_C_COPY]]
// CHECK: [[RET:%.*]] = init_existential_ref [[CAST_C_COPY_COPY]]
// CHECK: end_borrow [[BORROWED_CAST_C_COPY]]
// CHECK: destroy_value [[CAST_C_COPY]]
// CHECK: br [[CONT]]([[RET]] : $AnyObject)
d()
return y
// CHECK: [[IS_NOT_C]]([[NOCAST_C:%.*]] : @guaranteed $B):
// CHECK: end_borrow [[NOCAST_C]]
default:
// CHECK: function_ref @$s6switch1eyyF
// CHECK: [[X_COPY_2:%.*]] = copy_value [[X]]
// CHECK: [[RET:%.*]] = init_existential_ref [[X_COPY_2]]
// CHECK: br [[CONT]]([[RET]] : $AnyObject)
e()
return x
}
// CHECK: [[CONT]]([[T0:%.*]] : @owned $AnyObject):
// CHECK: return [[T0]]
}
// CHECK: } // end sil function '$s6switch16test_isa_class_21xyXlAA1BC_tF'
enum MaybePair {
case Neither
case Left(Int)
case Right(String)
case Both(Int, String)
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch12test_union_11uyAA9MaybePairO_tF
func test_union_1(u: MaybePair) {
switch u {
// CHECK: switch_enum [[SUBJECT:%.*]] : $MaybePair,
// CHECK: case #MaybePair.Neither!enumelt: [[IS_NEITHER:bb[0-9]+]],
// CHECK: case #MaybePair.Left!enumelt.1: [[IS_LEFT:bb[0-9]+]],
// CHECK: case #MaybePair.Right!enumelt.1: [[IS_RIGHT:bb[0-9]+]],
// CHECK: case #MaybePair.Both!enumelt.1: [[IS_BOTH:bb[0-9]+]]
// CHECK: [[IS_NEITHER]]:
// CHECK-NOT: destroy_value
case .Neither:
// CHECK: function_ref @$s6switch1ayyF
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[IS_LEFT]]({{%.*}}):
// CHECK-NOT: destroy_value
case (.Left):
// CHECK: function_ref @$s6switch1byyF
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_RIGHT]]([[STR:%.*]] : @guaranteed $String):
case var .Right:
// CHECK: function_ref @$s6switch1cyyF
// CHECK: br [[CONT]]
c()
// CHECK: [[IS_BOTH]]([[TUP:%.*]] : @guaranteed $(Int, String)):
case .Both:
// CHECK: ({{%.*}}, [[TUP_STR:%.*]]) = destructure_tuple [[TUP]]
// CHECK: function_ref @$s6switch1dyyF
// CHECK: br [[CONT]]
d()
}
// CHECK: [[CONT]]:
// CHECK-NOT: switch_enum [[SUBJECT]]
// CHECK: function_ref @$s6switch1eyyF
e()
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch12test_union_31uyAA9MaybePairO_tF : $@convention(thin) (@guaranteed MaybePair) -> () {
func test_union_3(u: MaybePair) {
// CHECK: bb0([[ARG:%.*]] : @guaranteed $MaybePair):
// CHECK: switch_enum [[ARG]] : $MaybePair,
// CHECK: case #MaybePair.Neither!enumelt: [[IS_NEITHER:bb[0-9]+]],
// CHECK: case #MaybePair.Left!enumelt.1: [[IS_LEFT:bb[0-9]+]],
// CHECK: case #MaybePair.Right!enumelt.1: [[IS_RIGHT:bb[0-9]+]],
// CHECK: default [[DEFAULT:bb[0-9]+]]
switch u {
// CHECK: [[IS_NEITHER]]:
case .Neither:
// CHECK: function_ref @$s6switch1ayyF
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[IS_LEFT]]({{%.*}}):
case .Left:
// CHECK: function_ref @$s6switch1byyF
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_RIGHT]]([[STR:%.*]] : @guaranteed $String):
case .Right:
// CHECK: function_ref @$s6switch1cyyF
// CHECK: br [[CONT]]
c()
// CHECK: [[DEFAULT]](
// -- Ensure the fully-opaque value is destroyed in the default case.
// CHECK: function_ref @$s6switch1dyyF
// CHECK: br [[CONT]]
default:
d()
}
// CHECK: [[CONT]]:
// CHECK-NOT: switch_enum [[ARG]]
// CHECK: function_ref @$s6switch1eyyF
e()
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch12test_union_41uyAA9MaybePairO_tF
func test_union_4(u: MaybePair) {
switch u {
// CHECK: switch_enum {{%.*}} : $MaybePair,
// CHECK: case #MaybePair.Neither!enumelt: [[IS_NEITHER:bb[0-9]+]],
// CHECK: case #MaybePair.Left!enumelt.1: [[IS_LEFT:bb[0-9]+]],
// CHECK: case #MaybePair.Right!enumelt.1: [[IS_RIGHT:bb[0-9]+]],
// CHECK: case #MaybePair.Both!enumelt.1: [[IS_BOTH:bb[0-9]+]]
// CHECK: [[IS_NEITHER]]:
case .Neither:
// CHECK: function_ref @$s6switch1ayyF
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[IS_LEFT]]({{%.*}}):
case .Left(_):
// CHECK: function_ref @$s6switch1byyF
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_RIGHT]]({{%.*}}):
case .Right(_):
// CHECK: function_ref @$s6switch1cyyF
// CHECK: br [[CONT]]
c()
// CHECK: [[IS_BOTH]]({{%.*}}):
case .Both(_):
// CHECK: function_ref @$s6switch1dyyF
// CHECK: br [[CONT]]
d()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @$s6switch1eyyF
e()
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch12test_union_51uyAA9MaybePairO_tF
func test_union_5(u: MaybePair) {
switch u {
// CHECK: switch_enum {{%.*}} : $MaybePair,
// CHECK: case #MaybePair.Neither!enumelt: [[IS_NEITHER:bb[0-9]+]],
// CHECK: case #MaybePair.Left!enumelt.1: [[IS_LEFT:bb[0-9]+]],
// CHECK: case #MaybePair.Right!enumelt.1: [[IS_RIGHT:bb[0-9]+]],
// CHECK: case #MaybePair.Both!enumelt.1: [[IS_BOTH:bb[0-9]+]]
// CHECK: [[IS_NEITHER]]:
case .Neither:
// CHECK: function_ref @$s6switch1ayyF
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[IS_LEFT]]({{%.*}}):
case .Left(_):
// CHECK: function_ref @$s6switch1byyF
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_RIGHT]]({{%.*}}):
case .Right(_):
// CHECK: function_ref @$s6switch1cyyF
// CHECK: br [[CONT]]
c()
// CHECK: [[IS_BOTH]]({{%.*}}):
case .Both(_, _):
// CHECK: function_ref @$s6switch1dyyF
// CHECK: br [[CONT]]
d()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @$s6switch1eyyF
e()
}
enum MaybeAddressOnlyPair {
case Neither
case Left(P)
case Right(String)
case Both(P, String)
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch22test_union_addr_only_11uyAA20MaybeAddressOnlyPairO_tF
func test_union_addr_only_1(u: MaybeAddressOnlyPair) {
switch u {
// CHECK: switch_enum_addr [[ENUM_ADDR:%.*]] : $*MaybeAddressOnlyPair,
// CHECK: case #MaybeAddressOnlyPair.Neither!enumelt: [[IS_NEITHER:bb[0-9]+]],
// CHECK: case #MaybeAddressOnlyPair.Left!enumelt.1: [[IS_LEFT:bb[0-9]+]],
// CHECK: case #MaybeAddressOnlyPair.Right!enumelt.1: [[IS_RIGHT:bb[0-9]+]],
// CHECK: case #MaybeAddressOnlyPair.Both!enumelt.1: [[IS_BOTH:bb[0-9]+]]
// CHECK: [[IS_NEITHER]]:
case .Neither:
// CHECK: function_ref @$s6switch1ayyF
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[IS_LEFT]]:
// CHECK: [[P:%.*]] = unchecked_take_enum_data_addr [[ENUM_ADDR]] : $*MaybeAddressOnlyPair, #MaybeAddressOnlyPair.Left!enumelt.1
case .Left(_):
// CHECK: [[FUNC:%.*]] = function_ref @$s6switch1byyF
// CHECK-NEXT: apply [[FUNC]](
// CHECK: destroy_addr [[P]]
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_RIGHT]]:
// CHECK: [[STR_ADDR:%.*]] = unchecked_take_enum_data_addr [[ENUM_ADDR]] : $*MaybeAddressOnlyPair, #MaybeAddressOnlyPair.Right!enumelt.1
// CHECK: [[STR:%.*]] = load [take] [[STR_ADDR]]
case .Right(_):
// CHECK: [[FUNC:%.*]] = function_ref @$s6switch1cyyF
// CHECK: apply [[FUNC]](
// CHECK: destroy_value [[STR]] : $String
// CHECK: br [[CONT]]
c()
// CHECK: [[IS_BOTH]]:
// CHECK: [[P_STR_TUPLE:%.*]] = unchecked_take_enum_data_addr [[ENUM_ADDR]] : $*MaybeAddressOnlyPair, #MaybeAddressOnlyPair.Both!enumelt.1
case .Both(_):
// CHECK: [[FUNC:%.*]] = function_ref @$s6switch1dyyF
// CHECK-NEXT: apply [[FUNC]](
// CHECK: destroy_addr [[P_STR_TUPLE]]
// CHECK: br [[CONT]]
d()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @$s6switch1eyyF
e()
}
enum Generic<T, U> {
case Foo(T)
case Bar(U)
}
// Check that switching over a generic instance generates verified SIL.
func test_union_generic_instance(u: Generic<Int, String>) {
switch u {
case .Foo(var x):
a()
case .Bar(var y):
b()
}
c()
}
enum Foo { case A, B }
// CHECK-LABEL: sil hidden [ossa] @$s6switch05test_A11_two_unions1x1yyAA3FooO_AFtF
func test_switch_two_unions(x: Foo, y: Foo) {
// CHECK: [[T0:%.*]] = tuple (%0 : $Foo, %1 : $Foo)
// CHECK: ([[X:%.*]], [[Y:%.*]]) = destructure_tuple [[T0]]
// CHECK: switch_enum [[Y]] : $Foo, case #Foo.A!enumelt: [[IS_CASE1:bb[0-9]+]], default [[IS_NOT_CASE1:bb[0-9]+]]
switch (x, y) {
// CHECK: [[IS_CASE1]]:
case (_, Foo.A):
// CHECK: function_ref @$s6switch1ayyF
a()
// CHECK: [[IS_NOT_CASE1]](
// CHECK: switch_enum [[X]] : $Foo, case #Foo.B!enumelt: [[IS_CASE2:bb[0-9]+]], default [[IS_NOT_CASE2:bb[0-9]+]]
// CHECK: [[IS_CASE2]]:
case (Foo.B, _):
// CHECK: function_ref @$s6switch1byyF
b()
// CHECK: [[IS_NOT_CASE2]](
// CHECK: switch_enum [[Y]] : $Foo, case #Foo.B!enumelt: [[IS_CASE3:bb[0-9]+]], default [[UNREACHABLE:bb[0-9]+]]
// CHECK: [[IS_CASE3]]:
case (_, Foo.B):
// CHECK: function_ref @$s6switch1cyyF
c()
// CHECK: [[UNREACHABLE]](
// CHECK: unreachable
}
}
// <rdar://problem/14826416>
func rdar14826416<T, U>(t: T, u: U) {
switch t {
case is Int: markUsed("Int")
case is U: markUsed("U")
case _: markUsed("other")
}
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch12rdar14826416{{[_0-9a-zA-Z]*}}F
// CHECK: checked_cast_addr_br copy_on_success T in {{%.*}} : $*T to Int in {{%.*}} : $*Int, [[IS_INT:bb[0-9]+]], [[ISNT_INT:bb[0-9]+]]
// CHECK: [[ISNT_INT]]:
// CHECK: checked_cast_addr_br copy_on_success T in {{%.*}} : $*T to U in {{%.*}} : $*U, [[ISNT_INT_IS_U:bb[0-9]+]], [[ISNT_INT_ISNT_U:bb[0-9]+]]
// <rdar://problem/14835992>
class Rdar14835992 {}
class SubRdar14835992 : Rdar14835992 {}
// CHECK-LABEL: sil hidden [ossa] @$s6switch12rdar14835992{{[_0-9a-zA-Z]*}}F
func rdar14835992<T, U>(t: Rdar14835992, tt: T, uu: U) {
switch t {
case is SubRdar14835992: markUsed("Sub")
case is T: markUsed("T")
case is U: markUsed("U")
case _: markUsed("other")
}
}
// <rdar://problem/17272985>
enum ABC { case A, B, C }
// CHECK-LABEL: sil hidden [ossa] @$s6switch18testTupleWildcardsyyAA3ABCO_ADtF
// CHECK: ([[X:%.*]], [[Y:%.*]]) = destructure_tuple {{%.*}} : $(ABC, ABC)
// CHECK: switch_enum [[X]] : $ABC, case #ABC.A!enumelt: [[X_A:bb[0-9]+]], default [[X_NOT_A:bb[0-9]+]]
// CHECK: [[X_A]]:
// CHECK: function_ref @$s6switch1ayyF
// CHECK: [[X_NOT_A]](
// CHECK: switch_enum [[Y]] : $ABC, case #ABC.A!enumelt: [[Y_A:bb[0-9]+]], case #ABC.B!enumelt: [[Y_B:bb[0-9]+]], case #ABC.C!enumelt: [[Y_C:bb[0-9]+]]
// CHECK-NOT: default
// CHECK: [[Y_A]]:
// CHECK: function_ref @$s6switch1byyF
// CHECK: [[Y_B]]:
// CHECK: function_ref @$s6switch1cyyF
// CHECK: [[Y_C]]:
// CHECK: switch_enum [[X]] : $ABC, case #ABC.C!enumelt: [[X_C:bb[0-9]+]], default [[X_NOT_C:bb[0-9]+]]
// CHECK: [[X_C]]:
// CHECK: function_ref @$s6switch1dyyF
// CHECK: [[X_NOT_C]](
// CHECK: function_ref @$s6switch1eyyF
func testTupleWildcards(_ x: ABC, _ y: ABC) {
switch (x, y) {
case (.A, _):
a()
case (_, .A):
b()
case (_, .B):
c()
case (.C, .C):
d()
default:
e()
}
}
enum LabeledScalarPayload {
case Payload(name: Int)
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch24testLabeledScalarPayloadyypAA0cdE0OF
func testLabeledScalarPayload(_ lsp: LabeledScalarPayload) -> Any {
// CHECK: switch_enum {{%.*}}, case #LabeledScalarPayload.Payload!enumelt.1: bb1
switch lsp {
// CHECK: bb1([[TUPLE:%.*]] : $(name: Int)):
// CHECK: [[X:%.*]] = destructure_tuple [[TUPLE]]
// CHECK: [[ANY_X_ADDR:%.*]] = init_existential_addr {{%.*}}, $Int
// CHECK: store [[X]] to [trivial] [[ANY_X_ADDR]]
case let .Payload(x):
return x
}
}
// There should be no unreachable generated.
// CHECK-LABEL: sil hidden [ossa] @$s6switch19testOptionalPatternyySiSgF
func testOptionalPattern(_ value : Int?) {
// CHECK: switch_enum %0 : $Optional<Int>, case #Optional.some!enumelt.1: bb1, case #Optional.none!enumelt: [[NILBB:bb[0-9]+]]
switch value {
case 1?: a()
case 2?: b()
case nil: d()
default: e()
}
}
// x? and .none should both be considered "similar" and thus handled in the same
// switch on the enum kind. There should be no unreachable generated.
// CHECK-LABEL: sil hidden [ossa] @$s6switch19testOptionalEnumMixyS2iSgF
func testOptionalEnumMix(_ a : Int?) -> Int {
// CHECK: debug_value %0 : $Optional<Int>, let, name "a"
// CHECK-NEXT: switch_enum %0 : $Optional<Int>, case #Optional.some!enumelt.1: [[SOMEBB:bb[0-9]+]], case #Optional.none!enumelt: [[NILBB:bb[0-9]+]]
switch a {
case let x?:
return 0
// CHECK: [[SOMEBB]](%3 : $Int):
// CHECK-NEXT: debug_value %3 : $Int, let, name "x"
// CHECK: integer_literal $Builtin.IntLiteral, 0
case .none:
return 42
// CHECK: [[NILBB]]:
// CHECK: integer_literal $Builtin.IntLiteral, 42
}
}
// x? and nil should both be considered "similar" and thus handled in the same
// switch on the enum kind. There should be no unreachable generated.
// CHECK-LABEL: sil hidden [ossa] @$s6switch26testOptionalEnumMixWithNilyS2iSgF
func testOptionalEnumMixWithNil(_ a : Int?) -> Int {
// CHECK: debug_value %0 : $Optional<Int>, let, name "a"
// CHECK-NEXT: switch_enum %0 : $Optional<Int>, case #Optional.some!enumelt.1: [[SOMEBB:bb[0-9]+]], case #Optional.none!enumelt: [[NILBB:bb[0-9]+]]
switch a {
case let x?:
return 0
// CHECK: [[SOMEBB]](%3 : $Int):
// CHECK-NEXT: debug_value %3 : $Int, let, name "x"
// CHECK: integer_literal $Builtin.IntLiteral, 0
case nil:
return 42
// CHECK: [[NILBB]]:
// CHECK: integer_literal $Builtin.IntLiteral, 42
}
}
// SR-3518
// CHECK-LABEL: sil hidden [ossa] @$s6switch43testMultiPatternsWithOuterScopeSameNamedVar4base6filterySiSg_AEtF
func testMultiPatternsWithOuterScopeSameNamedVar(base: Int?, filter: Int?) {
switch(base, filter) {
case (.some(let base), .some(let filter)):
// CHECK: bb2(%10 : $Int):
// CHECK-NEXT: debug_value %8 : $Int, let, name "base"
// CHECK-NEXT: debug_value %10 : $Int, let, name "filter"
print("both: \(base), \(filter)")
case (.some(let base), .none), (.none, .some(let base)):
// CHECK: bb3:
// CHECK-NEXT: debug_value %8 : $Int, let, name "base"
// CHECK-NEXT: br bb6(%8 : $Int)
// CHECK: bb5([[OTHER_BASE:%.*]] : $Int)
// CHECK-NEXT: debug_value [[OTHER_BASE]] : $Int, let, name "base"
// CHECK-NEXT: br bb6([[OTHER_BASE]] : $Int)
// CHECK: bb6([[ARG:%.*]] : $Int):
print("single: \(base)")
default:
print("default")
}
}
// All cases are unreachable, either structurally (tuples involving Never) or
// nominally (empty enums). We fold all of these to 'unreachable'.
enum MyNever {}
func ~= (_ : MyNever, _ : MyNever) -> Bool { return true }
func myFatalError() -> MyNever { fatalError("asdf") }
func testUninhabitedSwitchScrutinee() {
func test1(x : MyNever) {
// CHECK: bb0(%0 : $MyNever):
// CHECK-NEXT: debug_value %0 : $MyNever, let, name "x"
// CHECK-NEXT: unreachable
switch x {
case myFatalError(): break
case myFatalError(): break
case myFatalError(): break
}
}
func test2(x : Never) {
// CHECK: bb0(%0 : $Never):
// CHECK-NEXT: debug_value %0 : $Never, let, name "x"
// CHECK-NEXT: unreachable
switch (x, x) {}
}
func test3(x : Never) {
// CHECK: unreachable
// CHECK-NEXT: } // end sil function '$s6switch30testUninhabitedSwitchScrutineeyyF5test3L_1xys5NeverO_tF'
switch (x, 5, x) {}
}
func test4(x : Never) {
// CHECK: unreachable
// CHECK-NEXT: } // end sil function '$s6switch30testUninhabitedSwitchScrutineeyyF5test4L_1xys5NeverO_tF'
switch ((8, 6, 7), (5, 3, (0, x))) {}
}
func test5() {
// CHECK: %0 = function_ref @$s6switch12myFatalErrorAA7MyNeverOyF : $@convention(thin) () -> MyNever
// CHECK-NEXT: %1 = apply %0() : $@convention(thin) () -> MyNever
// CHECK-NEXT: unreachable
switch myFatalError() {}
}
}
// Make sure that we properly can handle address only tuples with loadable
// subtypes.
class Klass {}
enum TrivialSingleCaseEnum {
case a
}
enum NonTrivialSingleCaseEnum {
case a(Klass)
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch33address_only_with_trivial_subtypeyyAA21TrivialSingleCaseEnumO_yptF : $@convention(thin) (TrivialSingleCaseEnum, @in_guaranteed Any) -> () {
// CHECK: [[MEM:%.*]] = alloc_stack $(TrivialSingleCaseEnum, Any)
// CHECK: [[INIT_TUP_0:%.*]] = tuple_element_addr [[MEM]] : $*(TrivialSingleCaseEnum, Any), 0
// CHECK: [[INIT_TUP_1:%.*]] = tuple_element_addr [[MEM]] : $*(TrivialSingleCaseEnum, Any), 1
// CHECK: store {{%.*}} to [trivial] [[INIT_TUP_0]]
// CHECK: copy_addr [take] {{%.*}} to [initialization] [[INIT_TUP_1]]
// CHECK: [[TUP_0:%.*]] = tuple_element_addr [[MEM]] : $*(TrivialSingleCaseEnum, Any), 0
// CHECK: [[TUP_0_VAL:%.*]] = load [trivial] [[TUP_0]]
// CHECK: [[TUP_1:%.*]] = tuple_element_addr [[MEM]] : $*(TrivialSingleCaseEnum, Any), 1
// CHECK: switch_enum [[TUP_0_VAL]]
//
// CHECK: } // end sil function '$s6switch33address_only_with_trivial_subtypeyyAA21TrivialSingleCaseEnumO_yptF'
func address_only_with_trivial_subtype(_ a: TrivialSingleCaseEnum, _ value: Any) {
switch (a, value) {
case (.a, _):
break
default:
break
}
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch36address_only_with_nontrivial_subtypeyyAA24NonTrivialSingleCaseEnumO_yptF : $@convention(thin) (@guaranteed NonTrivialSingleCaseEnum, @in_guaranteed Any) -> () {
// CHECK: [[MEM:%.*]] = alloc_stack $(NonTrivialSingleCaseEnum, Any)
// CHECK: [[INIT_TUP_0:%.*]] = tuple_element_addr [[MEM]] : $*(NonTrivialSingleCaseEnum, Any), 0
// CHECK: [[INIT_TUP_1:%.*]] = tuple_element_addr [[MEM]] : $*(NonTrivialSingleCaseEnum, Any), 1
// CHECK: store {{%.*}} to [init] [[INIT_TUP_0]]
// CHECK: copy_addr [take] {{%.*}} to [initialization] [[INIT_TUP_1]]
// CHECK: [[TUP_0:%.*]] = tuple_element_addr [[MEM]] : $*(NonTrivialSingleCaseEnum, Any), 0
// CHECK: [[TUP_0_VAL:%.*]] = load_borrow [[TUP_0]]
// CHECK: [[TUP_1:%.*]] = tuple_element_addr [[MEM]] : $*(NonTrivialSingleCaseEnum, Any), 1
// CHECK: switch_enum [[TUP_0_VAL]]
//
// CHECK: bb1([[CASE_VAL:%.*]] :
// CHECK-NEXT: end_borrow [[CASE_VAL]]
// CHECK-NEXT: destroy_addr [[TUP_1]]
// CHECK-NEXT: end_borrow [[TUP_0_VAL]]
// CHECK-NEXT: destroy_addr [[TUP_0]]
// CHECK-NEXT: dealloc_stack [[MEM]]
//
// CHECK: bb2:
// CHECK-NEXT: destroy_addr [[MEM]]
// CHECK-NEXT: dealloc_stack [[MEM]]
// CHECK: } // end sil function '$s6switch36address_only_with_nontrivial_subtypeyyAA24NonTrivialSingleCaseEnumO_yptF'
func address_only_with_nontrivial_subtype(_ a: NonTrivialSingleCaseEnum, _ value: Any) {
switch (a, value) {
case (.a, _):
break
default:
break
}
}
// This test makes sure that when we have a tuple that is partly address only
// and partially an object that even though we access the object at +0 via a
// load_borrow, we do not lose the +1 from the original tuple formation.
// CHECK-LABEL: sil hidden [ossa] @$s6switch35partial_address_only_tuple_dispatchyyAA5KlassC_ypSgtF : $@convention(thin) (@guaranteed Klass, @in_guaranteed Optional<Any>) -> () {
// CHECK: bb0([[ARG0:%.*]] : @guaranteed $Klass, [[ARG1:%.*]] : $*Optional<Any>):
// CHECK: [[ARG0_COPY:%.*]] = copy_value [[ARG0]]
// CHECK: [[ARG1_COPY:%.*]] = alloc_stack $Optional<Any>
// CHECK: copy_addr [[ARG1]] to [initialization] [[ARG1_COPY]]
// CHECK: [[TUP:%.*]] = alloc_stack $(Klass, Optional<Any>)
// CHECK: [[TUP_0:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional<Any>), 0
// CHECK: [[TUP_1:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional<Any>), 1
// CHECK: store [[ARG0_COPY]] to [init] [[TUP_0]]
// CHECK: copy_addr [take] [[ARG1_COPY]] to [initialization] [[TUP_1]]
// CHECK: [[TUP_0:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional<Any>), 0
// CHECK: [[TUP_0_VAL:%.*]] = load_borrow [[TUP_0]]
// CHECK: [[TUP_1:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional<Any>), 1
// CHECK: destroy_addr [[TUP_1]]
// CHECK: end_borrow [[TUP_0_VAL]]
// CHECK: destroy_addr [[TUP_0]]
// CHECK: dealloc_stack [[TUP]]
// CHECK: br bb2
//
// CHECK: bb1:
// CHECK: destroy_addr [[TUP]]
// CHECK: dealloc_stack [[TUP]]
// CHECK: } // end sil function '$s6switch35partial_address_only_tuple_dispatchyyAA5KlassC_ypSgtF'
func partial_address_only_tuple_dispatch(_ name: Klass, _ value: Any?) {
switch (name, value) {
case (_, _):
break
default:
break
}
}
// CHECK-LABEL: sil hidden [ossa] @$s6switch50partial_address_only_tuple_dispatch_with_fail_caseyyAA5KlassC_ypSgtF : $@convention(thin) (@guaranteed Klass, @in_guaranteed Optional<Any>) -> () {
// CHECK: bb0([[ARG0:%.*]] : @guaranteed $Klass, [[ARG1:%.*]] : $*Optional<Any>):
// CHECK: [[ARG0_COPY:%.*]] = copy_value [[ARG0]]
// CHECK: [[ARG1_COPY:%.*]] = alloc_stack $Optional<Any>
// CHECK: copy_addr [[ARG1]] to [initialization] [[ARG1_COPY]]
// CHECK: [[TUP:%.*]] = alloc_stack $(Klass, Optional<Any>)
// CHECK: [[TUP_0:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional<Any>), 0
// CHECK: [[TUP_1:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional<Any>), 1
// CHECK: store [[ARG0_COPY]] to [init] [[TUP_0]]
// CHECK: copy_addr [take] [[ARG1_COPY]] to [initialization] [[TUP_1]]
// CHECK: [[TUP_0:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional<Any>), 0
// CHECK: [[TUP_0_VAL:%.*]] = load_borrow [[TUP_0]]
// CHECK: [[TUP_1:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional<Any>), 1
// CHECK: checked_cast_br [[TUP_0_VAL]] : $Klass to $AnyObject, [[IS_ANYOBJECT_BB:bb[0-9]+]], [[ISNOT_ANYOBJECT_BB:bb[0-9]+]]
//
// CHECK: [[IS_ANYOBJECT_BB]]([[ANYOBJECT:%.*]] : @guaranteed $AnyObject):
// CHECK: [[ANYOBJECT_COPY:%.*]] = copy_value [[ANYOBJECT]]
// ... CASE BODY ...
// CHECK: destroy_addr [[TUP_1]]
// CHECK: end_borrow [[TUP_0_VAL]]
// CHECK: destroy_addr [[TUP_0]]
// CHECK: dealloc_stack [[TUP]]
// CHECK: br [[EXIT_BB:bb[0-9]+]]
//
// CHECK: [[ISNOT_ANYOBJECT_BB]](
// CHECK: switch_enum_addr [[TUP_1]] : $*Optional<Any>, case #Optional.some!enumelt.1: [[HAS_TUP_1_BB:bb[0-9]+]], default [[NO_TUP_1_BB:bb[0-9]+]]
//
// CHECK: [[HAS_TUP_1_BB]]:
// CHECK-NEXT: [[OPT_ANY_ADDR:%.*]] = alloc_stack $Optional<Any>
// CHECK-NEXT: copy_addr [[TUP_1]] to [initialization] [[OPT_ANY_ADDR]]
// CHECK-NEXT: [[SOME_ANY_ADDR:%.*]] = unchecked_take_enum_data_addr [[OPT_ANY_ADDR]]
// CHECK-NEXT: [[ANYOBJECT_ADDR:%.*]] = alloc_stack $AnyObject
// CHECK-NEXT: checked_cast_addr_br copy_on_success Any in {{%.*}} : $*Any to AnyObject in {{%.*}} : $*AnyObject, [[IS_ANY_BB:bb[0-9]+]], [[ISNOT_ANY_BB:bb[0-9]+]]
//
// Make sure that we clean up everything here. We are exiting here.
//
// CHECK: [[IS_ANY_BB]]:
// CHECK-NEXT: [[ANYOBJECT:%.*]] = load [take] [[ANYOBJECT_ADDR]]
// CHECK-NEXT: debug_value
// CHECK-NEXT: destroy_value [[ANYOBJECT]]
// CHECK-NEXT: dealloc_stack [[ANYOBJECT_ADDR]]
// CHECK-NEXT: destroy_addr [[SOME_ANY_ADDR]]
// CHECK-NEXT: dealloc_stack [[OPT_ANY_ADDR]]
// CHECK-NEXT: destroy_addr [[TUP_1]]
// CHECK-NEXT: end_borrow [[TUP_0_VAL]]
// CHECK-NEXT: destroy_addr [[TUP_0]]
// CHECK-NEXT: dealloc_stack [[TUP]]
// CHECK-NEXT: dealloc_stack
// CHECK-NEXT: br [[EXIT_BB]]
//
// CHECK: [[ISNOT_ANY_BB]]:
// CHECK-NEXT: dealloc_stack [[ANYOBJECT_ADDR]]
// CHECK-NEXT: destroy_addr [[SOME_ANY_ADDR]]
// CHECK-NEXT: dealloc_stack [[OPT_ANY_ADDR]]
// CHECK-NEXT: end_borrow
// CHECK-NEXT: br [[UNFORWARD_BB:bb[0-9]+]]
//
// CHECK: [[NO_TUP_1_BB]]:
// CHECK-NEXT: end_borrow
// CHECK-NEXT: br [[UNFORWARD_BB]]
//
// CHECK: [[UNFORWARD_BB]]:
// CHECK-NEXT: destroy_addr [[TUP]]
// CHECK-NEXT: dealloc_stack [[TUP]]
// CHECK: br [[EXIT_BB]]
//
// CHECK: [[EXIT_BB]]:
// ...
// CHECK: } // end sil function '$s6switch50partial_address_only_tuple_dispatch_with_fail_caseyyAA5KlassC_ypSgtF'
func partial_address_only_tuple_dispatch_with_fail_case(_ name: Klass, _ value: Any?) {
switch (name, value) {
case let (x as AnyObject, _):
break
case let (_, y as AnyObject):
break
default:
break
}
}
// This was crashing the ownership verifier at some point and was reported in
// SR-6664. Just make sure that we still pass the ownership verifier.
// `indirect` is necessary; generic parameter is necessary.
indirect enum SR6664_Base<Element> {
// Tuple associated value is necessary; one element must be a function,
// the other must be a non-function using the generic parameter.
// (The original associated value was `(where: (Element) -> Bool, of: Element?)`,
// to give you an idea of the variety of types.)
case index((Int) -> Void, Element)
// Function can be in an extension or not. Can have a return value or not. Can
// have a parameter or not. Can be generic or not.
func relative() {
switch self {
// Matching the case is necessary. You can capture or ignore the associated
// values.
case .index:
// Body doesn't matter.
break
}
}
}
// Make sure that we properly create switch_enum success arguments if we have an
// associated type that is a void type.
func testVoidType() {
let x: Optional<()> = ()
switch x {
case .some(let x):
break
case .none:
break
}
}