Files
swift-mirror/test/SILGen/switch.swift
Adrian Prantl 64cbec3805 Add SIL syntax for declaring debug variables.
Debug variable info may be attached to debug_value, debug_value_addr,
alloc_box, and alloc_stack instructions.

In order to write textual SIL -> SIL testcases that exercise the handling
of debug information by SIL passes, we need to make a couple of additions
to the textual SIL language. In memory, the debug information attached to
SIL instructions references information from the AST. If we want to create
debug info from parsing a textual .sil file, these bits need to be made
explicit.

Performance Notes: This is memory neutral for compilations from Swift
source code, because the variable name is still stored in the AST. For
compilations from textual source the variable name is stored in tail-
allocated memory following the SIL instruction that introduces the
variable.

<rdar://problem/22707128>
2015-12-14 10:29:50 -08:00

1278 lines
37 KiB
Swift

// RUN: %target-swift-frontend -enable-experimental-patterns -emit-silgen %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 @_TF6switch5test1FT_T_
func test1() {
switch foo() {
// CHECK: function_ref @_TF6switch3fooFT_Si
case _:
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1bFT_T_
b()
}
// CHECK-LABEL: sil hidden @_TF6switch5test2FT_T_
func test2() {
switch foo() {
// CHECK: function_ref @_TF6switch3fooFT_Si
case _:
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
case _: // The second case is unreachable.
b()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1cFT_T_
c()
}
// CHECK-LABEL: sil hidden @_TF6switch5test3FT_T_
func test3() {
switch foo() {
// CHECK: function_ref @_TF6switch3fooFT_Si
// CHECK: function_ref @_TF6switch6runcedFT_Sb
// CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE2:bb[0-9]+]]
case _ where runced():
// CHECK: [[CASE1]]:
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[NO_CASE2]]:
// CHECK: br [[CASE2:bb[0-9]+]]
case _:
// CHECK: [[CASE2]]:
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1cFT_T_
c()
}
// CHECK-LABEL: sil hidden @_TF6switch5test4FT_T_
func test4() {
switch (foo(), bar()) {
// CHECK: function_ref @_TF6switch3fooFT_Si
// CHECK: function_ref @_TF6switch3barFT_Si
case _:
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1bFT_T_
b()
}
// CHECK-LABEL: sil hidden @_TF6switch5test5FT_T_
func test5() {
switch (foo(), bar()) {
// CHECK: function_ref @_TF6switch3fooFT_Si
// CHECK: function_ref @_TF6switch3barFT_Si
// CHECK: function_ref @_TF6switch6runcedFT_Sb
// CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
case _ where runced():
// CHECK: [[CASE1]]:
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[NOT_CASE1]]:
// CHECK: function_ref @_TF6switch6fungedFT_Sb
// CHECK: cond_br {{%.*}}, [[YES_CASE2:bb[0-9]+]], [[NOT_CASE2:bb[0-9]+]]
// CHECK: [[YES_CASE2]]:
case (_, _) where funged():
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
// CHECK: [[NOT_CASE2]]:
// CHECK: br [[CASE3:bb[0-9]+]]
case _:
// CHECK: [[CASE3]]:
// CHECK: function_ref @_TF6switch1cFT_T_
// CHECK: br [[CONT]]
c()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1dFT_T_
d()
}
// CHECK-LABEL: sil hidden @_TF6switch5test6FT_T_
func test6() {
switch (foo(), bar()) {
// CHECK: function_ref @_TF6switch3fooFT_Si
// CHECK: function_ref @_TF6switch3barFT_Si
case (_, _):
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
case (_, _): // The second case is unreachable.
b()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1cFT_T_
c()
}
// CHECK-LABEL: sil hidden @_TF6switch5test7FT_T_
func test7() {
switch (foo(), bar()) {
// CHECK: function_ref @_TF6switch3fooFT_Si
// CHECK: function_ref @_TF6switch3barFT_Si
// CHECK: function_ref @_TF6switch6runcedFT_Sb
// CHECK: cond_br {{%.*}}, [[YES_CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
// CHECK: [[YES_CASE1]]:
case (_, _) where runced():
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[NOT_CASE1]]:
// CHECK: br [[CASE2:bb[0-9]+]]
case (_, _):
// CHECK: [[CASE2]]:
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
}
c()
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1cFT_T_
}
// CHECK-LABEL: sil hidden @_TF6switch5test8FT_T_
func test8() {
switch (foo(), bar()) {
// CHECK: function_ref @_TF6switch3fooFT_Si
// CHECK: function_ref @_TF6switch3barFT_Si
// CHECK: function_ref @_TF6switch6foobarFT_TSiSi_
// CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
case foobar():
// CHECK: [[CASE1]]:
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[NOT_CASE1]]:
// CHECK: function_ref @_TF6switch3fooFT_Si
// CHECK: cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NOT_CASE2:bb[0-9]+]]
case (foo(), _):
// CHECK: [[CASE2]]:
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
// CHECK: [[NOT_CASE2]]:
// CHECK: function_ref @_TF6switch3barFT_Si
// CHECK: cond_br {{%.*}}, [[CASE3_GUARD:bb[0-9]+]], [[NOT_CASE3:bb[0-9]+]]
// CHECK: [[CASE3_GUARD]]:
// CHECK: function_ref @_TF6switch6runcedFT_Sb
// CHECK: cond_br {{%.*}}, [[CASE3:bb[0-9]+]], [[NOT_CASE3_GUARD:bb[0-9]+]]
case (_, bar()) where runced():
// CHECK: [[CASE3]]:
// CHECK: function_ref @_TF6switch1cFT_T_
// CHECK: br [[CONT]]
c()
// CHECK: [[NOT_CASE3_GUARD]]:
// CHECK: [[NOT_CASE3]]:
// CHECK: function_ref @_TF6switch3fooFT_Si
// CHECK: cond_br {{%.*}}, [[CASE4_GUARD_1:bb[0-9]+]], [[NOT_CASE4_1:bb[0-9]+]]
// CHECK: [[CASE4_GUARD_1]]:
// CHECK: function_ref @_TF6switch3barFT_Si
// CHECK: cond_br {{%.*}}, [[CASE4_GUARD_2:bb[0-9]+]], [[NOT_CASE4_2:bb[0-9]+]]
// CHECK: [[CASE4_GUARD_2]]:
// CHECK: function_ref @_TF6switch6fungedFT_Sb
// CHECK: cond_br {{%.*}}, [[CASE4:bb[0-9]+]], [[NOT_CASE4_3:bb[0-9]+]]
case (foo(), bar()) where funged():
// CHECK: [[CASE4]]:
// CHECK: function_ref @_TF6switch1dFT_T_
// CHECK: br [[CONT]]
d()
// CHECK: [[NOT_CASE4_3]]:
// CHECK: [[NOT_CASE4_2]]:
// CHECK: [[NOT_CASE4_1]]:
// CHECK: function_ref @_TF6switch3fooFT_Si
// CHECK: cond_br {{%.*}}, [[CASE5_GUARD_1:bb[0-9]+]], [[NOT_CASE5:bb[0-9]+]]
// CHECK: [[CASE5_GUARD_1]]:
// CHECK: function_ref @_TF6switch3barFT_Si
// CHECK: cond_br {{%.*}}, [[YES_CASE5:bb[0-9]+]], [[NOT_CASE5:bb[0-9]+]]
// CHECK: [[YES_CASE5]]:
case (foo(), bar()):
// CHECK: function_ref @_TF6switch1eFT_T_
// CHECK: br [[CONT]]
e()
// CHECK: [[NOT_CASE5]]:
// CHECK: br [[CASE6:bb[0-9]+]]
case _:
// CHECK: [[CASE6]]:
// CHECK: function_ref @_TF6switch1fFT_T_
// CHECK: br [[CONT]]
f()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1gFT_T_
g()
}
// CHECK-LABEL: sil hidden @_TF6switch5test9FT_T_
func test9() {
switch (foo(), bar()) {
// CHECK: function_ref @_TF6switch3fooFT_Si
// CHECK: function_ref @_TF6switch3barFT_Si
// CHECK: function_ref @_TF6switch3fooFT_Si
// CHECK: cond_br {{%.*}}, [[YES_CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
// CHECK: [[YES_CASE1]]:
case (foo(), _):
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[NOT_CASE1]]:
// CHECK: function_ref @_TF6switch6foobarFT_TSiSi_
// CHECK: cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NOT_CASE2:bb[0-9]+]]
case foobar():
// CHECK: [[CASE2]]:
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
// CHECK: [[NOT_CASE2]]:
// CHECK: br [[CASE3:bb[0-9]+]]
case _:
// CHECK: [[CASE3]]:
// CHECK: function_ref @_TF6switch1cFT_T_
// CHECK: br [[CONT]]
c()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1dFT_T_
d()
}
// CHECK-LABEL: sil hidden @_TF6switch6test10FT_T_
func test10() {
switch (foo(), bar()) {
// CHECK: function_ref @_TF6switch3fooFT_Si
// CHECK: function_ref @_TF6switch3barFT_Si
// CHECK: cond_br {{%.*}}, [[YES_CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
// CHECK: [[YES_CASE1]]:
case (foo()...bar(), _):
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[NOT_CASE1]]:
// CHECK: br [[CASE2:bb[0-9]+]]
case _:
// CHECK: [[CASE2]]:
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1cFT_T_
c()
}
protocol P { func p() }
struct X : P { func p() {} }
struct Y : P { func p() {} }
struct Z : P { func p() {} }
// CHECK-LABEL: sil hidden @_TF6switch10test_isa_1FT1pPS_1P__T_
func test_isa_1(p p: P) {
// CHECK: [[PTMPBUF:%[0-9]+]] = alloc_stack $P
// CHECK-NEXT: copy_addr %0 to [initialization] [[PTMPBUF]]#1 : $*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]]#1 : $*X, [[IS_X:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]]
case is X:
// CHECK: [[IS_X]]:
// CHECK-NEXT: load [[TMPBUF]]#1
// CHECK-NEXT: dealloc_stack [[TMPBUF]]#0
// CHECK-NEXT: destroy_addr [[PTMPBUF]]#1
// CHECK-NEXT: dealloc_stack [[PTMPBUF]]#0
a()
// CHECK: function_ref @_TF6switch1aFT_T_
// 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 @_TF6switch1bFT_T_
// 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 @_TF6switch1cFT_T_
// CHECK: br [[Z_CONT:bb[0-9]+]]
c()
// CHECK: [[IS_NOT_Z]]:
case _:
// CHECK: function_ref @_TF6switch1dFT_T_
// CHECK: br [[CONT]]
d()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1eFT_T_
e()
}
// CHECK-LABEL: sil hidden @_TF6switch10test_isa_2FT1pPS_1P__T_
func test_isa_2(p 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 @_TF6switch3fooFT_Si
// CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
case (is X, foo()):
// CHECK: [[CASE1]]:
// CHECK: function_ref @_TF6switch1aFT_T_
// 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 @_TF6switch3fooFT_Si
// CHECK: cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NOT_CASE2:bb[0-9]+]]
case (is Y, foo()):
// CHECK: [[CASE2]]:
// CHECK: function_ref @_TF6switch1bFT_T_
// 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 @_TF6switch1cFT_T_
// 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 @_TF6switch3barFT_Si
// CHECK: cond_br {{%.*}}, [[CASE4:bb[0-9]+]], [[NOT_CASE4:bb[0-9]+]]
case (is Y, bar()):
// CHECK: [[CASE4]]:
// CHECK: function_ref @_TF6switch1dFT_T_
// 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 @_TF6switch1eFT_T_
// CHECK: br [[CONT]]
e()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1fFT_T_
f()
}
class B {}
class C : B {}
class D1 : C {}
class D2 : D1 {}
class E : C {}
// CHECK-LABEL: sil hidden @_TF6switch16test_isa_class_1FT1xCS_1B_T_
func test_isa_class_1(x x: B) {
// CHECK: strong_retain %0
switch x {
// CHECK: checked_cast_br [[X:%.*]] : $B to $D1, [[IS_D1:bb[0-9]+]], [[IS_NOT_D1:bb[0-9]+]]
// CHECK: [[IS_D1]]([[CAST_D1:%.*]]):
// CHECK: function_ref @_TF6switch6runcedFT_Sb
// CHECK: cond_br {{%.*}}, [[YES_CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]]
// CHECK: [[YES_CASE1]]:
case is D1 where runced():
// CHECK: strong_release [[CAST_D1]]
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[NO_CASE1]]:
// CHECK: [[IS_NOT_D1]]:
// CHECK: checked_cast_br [[X]] : $B to $D2, [[IS_D2:bb[0-9]+]], [[IS_NOT_D2:bb[0-9]+]]
// CHECK: [[IS_D2]]([[CAST_D2:%.*]]):
case is D2:
// CHECK: strong_release %0
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_NOT_D2]]:
// CHECK: checked_cast_br [[X]] : $B to $E, [[IS_E:bb[0-9]+]], [[IS_NOT_E:bb[0-9]+]]
// CHECK: [[IS_E]]([[CAST_E:%.*]]):
// CHECK: function_ref @_TF6switch6fungedFT_Sb
// CHECK: cond_br {{%.*}}, [[CASE3:bb[0-9]+]], [[NO_CASE3:bb[0-9]+]]
case is E where funged():
// CHECK: [[CASE3]]:
// CHECK: function_ref @_TF6switch1cFT_T_
// CHECK: br [[CONT]]
c()
// CHECK: [[NO_CASE3]]:
// CHECK: [[IS_NOT_E]]:
// CHECK: checked_cast_br [[X]] : $B to $C, [[IS_C:bb[0-9]+]], [[IS_NOT_C:bb[0-9]+]]
// CHECK: [[IS_C]]([[CAST_C:%.*]]):
case is C:
// CHECK: function_ref @_TF6switch1dFT_T_
// CHECK: br [[CONT]]
d()
// CHECK: [[IS_NOT_C]]:
default:
// CHECK: strong_release [[X]]
// CHECK: function_ref @_TF6switch1eFT_T_
// CHECK: br [[CONT]]
e()
}
// CHECK: [[CONT]]:
// CHECK: strong_release %0
f()
}
// CHECK-LABEL: sil hidden @_TF6switch16test_isa_class_2FT1xCS_1B_Ps9AnyObject_
func test_isa_class_2(x x: B) -> AnyObject {
// CHECK: strong_retain [[X:%0]]
switch x {
// CHECK: checked_cast_br [[X]] : $B to $D1, [[IS_D1:bb[0-9]+]], [[IS_NOT_D1:bb[0-9]+]]
// CHECK: [[IS_D1]]([[CAST_D1:%.*]]):
// CHECK: strong_retain [[CAST_D1]]
// CHECK: function_ref @_TF6switch6runcedFT_Sb
// CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]]
case let y as D1 where runced():
// CHECK: [[CASE1]]:
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: [[RET:%.*]] = init_existential_ref [[CAST_D1]]
// CHECK: strong_release [[X]] : $B
// CHECK: br [[CONT:bb[0-9]+]]([[RET]] : $AnyObject)
a()
return y
// CHECK: [[NO_CASE1]]:
// CHECK: strong_release [[CAST_D1]]
// CHECK: [[IS_NOT_D1]]:
// 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:%.*]]):
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: [[RET:%.*]] = init_existential_ref [[CAST_D2]]
// CHECK: br [[CONT]]([[RET]] : $AnyObject)
b()
return y
// CHECK: [[IS_NOT_D2]]:
// CHECK: checked_cast_br [[X]] : $B to $E, [[IS_E:bb[0-9]+]], [[IS_NOT_E:bb[0-9]+]]
// CHECK: [[IS_E]]([[CAST_E:%.*]]):
// CHECK: strong_retain [[CAST_E]]
// CHECK: function_ref @_TF6switch6fungedFT_Sb
// CHECK: cond_br {{%.*}}, [[CASE3:bb[0-9]+]], [[NO_CASE3:bb[0-9]+]]
case let y as E where funged():
// CHECK: [[CASE3]]:
// CHECK: function_ref @_TF6switch1cFT_T_
// CHECK: [[RET:%.*]] = init_existential_ref [[CAST_E]]
// CHECK: strong_release [[X]] : $B
// CHECK: br [[CONT]]([[RET]] : $AnyObject)
c()
return y
// CHECK: [[NO_CASE3]]:
// CHECK strong_release [[CAST_E]]
// CHECK: [[IS_NOT_E]]:
// 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:%.*]]):
// CHECK: function_ref @_TF6switch1dFT_T_
// CHECK: [[RET:%.*]] = init_existential_ref [[CAST_C]]
// CHECK: br [[CONT]]([[RET]] : $AnyObject)
d()
return y
// CHECK: [[IS_NOT_C]]:
default:
// CHECK: function_ref @_TF6switch1eFT_T_
// CHECK: [[RET:%.*]] = init_existential_ref [[X]]
// CHECK: br [[CONT]]([[RET]] : $AnyObject)
e()
return x
}
// CHECK: [[CONT]]([[T0:%.*]] : $AnyObject):
// CHECK: strong_release [[X]]
// CHECK: return [[T0]]
}
enum MaybePair {
case Neither
case Left(Int)
case Right(String)
case Both(Int, String)
}
// CHECK-LABEL: sil hidden @_TF6switch12test_union_1FT1uOS_9MaybePair_T_
func test_union_1(u 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: release
case .Neither:
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[IS_LEFT]]({{%.*}}):
// CHECK-NOT: release
case (.Left):
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_RIGHT]]([[STR:%.*]] : $String):
case let .Right:
// CHECK: release_value [[STR]] : $String
// CHECK: function_ref @_TF6switch1cFT_T_
// CHECK: br [[CONT]]
c()
// CHECK: [[IS_BOTH]]([[TUP:%.*]] : $(Int, String)):
case .Both:
// CHECK: release_value [[TUP]] : $(Int, String)
// CHECK: function_ref @_TF6switch1dFT_T_
// CHECK: br [[CONT]]
d()
}
// CHECK: [[CONT]]:
// CHECK-NOT: switch_enum [[SUBJECT]]
// CHECK: function_ref @_TF6switch1eFT_T_
e()
}
// CHECK-LABEL: sil hidden @_TF6switch12test_union_2FT1uOS_9MaybePair_T_
func test_union_2(u 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: default [[DEFAULT:bb[0-9]+]]
// CHECK: [[IS_NEITHER]]:
case .Neither:
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[IS_LEFT]]({{%.*}}):
case .Left:
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_RIGHT]]({{%.*}}):
case .Right:
// CHECK: function_ref @_TF6switch1cFT_T_
// CHECK: br [[CONT]]
c()
// -- missing .Both case
// CHECK: [[DEFAULT]]:
// CHECK: unreachable
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1dFT_T_
d()
}
// CHECK-LABEL: sil hidden @_TF6switch12test_union_3FT1uOS_9MaybePair_T_
func test_union_3(u u: MaybePair) {
// CHECK: retain_value [[SUBJECT:%0]]
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: default [[DEFAULT:bb[0-9]+]]
// CHECK: [[IS_NEITHER]]:
case .Neither:
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[IS_LEFT]]({{%.*}}):
case .Left:
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_RIGHT]]([[STR:%.*]] : $String):
case .Right:
// CHECK: release_value [[STR]] : $String
// CHECK: function_ref @_TF6switch1cFT_T_
// CHECK: br [[CONT]]
c()
// CHECK: [[DEFAULT]]:
// -- Ensure the fully-opaque value is destroyed in the default case.
// CHECK: release_value [[SUBJECT]] :
// CHECK: function_ref @_TF6switch1dFT_T_
// CHECK: br [[CONT]]
default:
d()
}
// CHECK: [[CONT]]:
// CHECK-NOT: switch_enum [[SUBJECT]]
// CHECK: function_ref @_TF6switch1eFT_T_
// CHECK: release_value [[SUBJECT]]
e()
}
// CHECK-LABEL: sil hidden @_TF6switch12test_union_4FT1uOS_9MaybePair_T_
func test_union_4(u 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 @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[IS_LEFT]]({{%.*}}):
case .Left(_):
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_RIGHT]]({{%.*}}):
case .Right(_):
// CHECK: function_ref @_TF6switch1cFT_T_
// CHECK: br [[CONT]]
c()
// CHECK: [[IS_BOTH]]({{%.*}}):
case .Both(_):
// CHECK: function_ref @_TF6switch1dFT_T_
// CHECK: br [[CONT]]
d()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1eFT_T_
e()
}
// CHECK-LABEL: sil hidden @_TF6switch12test_union_5FT1uOS_9MaybePair_T_
func test_union_5(u 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 @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[IS_LEFT]]({{%.*}}):
case .Left(_):
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_RIGHT]]({{%.*}}):
case .Right(_):
// CHECK: function_ref @_TF6switch1cFT_T_
// CHECK: br [[CONT]]
c()
// CHECK: [[IS_BOTH]]({{%.*}}):
case .Both(_, _):
// CHECK: function_ref @_TF6switch1dFT_T_
// CHECK: br [[CONT]]
d()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1eFT_T_
e()
}
enum MaybeAddressOnlyPair {
case Neither
case Left(P)
case Right(String)
case Both(P, String)
}
// CHECK-LABEL: sil hidden @_TF6switch22test_union_addr_only_1FT1uOS_20MaybeAddressOnlyPair_T_
func test_union_addr_only_1(u 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 @_TF6switch1aFT_T_
// 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: destroy_addr [[P]]
// CHECK: function_ref @_TF6switch1bFT_T_
// 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 [[STR_ADDR]]
case .Right(_):
// CHECK: release_value [[STR]] : $String
// CHECK: function_ref @_TF6switch1cFT_T_
// 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: destroy_addr [[P_STR_TUPLE]]
// CHECK: function_ref @_TF6switch1dFT_T_
// CHECK: br [[CONT]]
d()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1eFT_T_
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 u: Generic<Int, String>) {
switch u {
case .Foo(let x):
a()
case .Bar(let y):
b()
}
c()
}
enum Foo { case A, B }
// CHECK-LABEL: sil hidden @_TF6switch22test_switch_two_unionsFT1xOS_3Foo1yS0__T_
func test_switch_two_unions(x x: Foo, y: Foo) {
// CHECK: [[T0:%.*]] = tuple (%0 : $Foo, %1 : $Foo)
// CHECK: [[X:%.*]] = tuple_extract [[T0]] : $(Foo, Foo), 0
// CHECK: [[Y:%.*]] = tuple_extract [[T0]] : $(Foo, Foo), 1
// 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 @_TF6switch1aFT_T_
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 @_TF6switch1bFT_T_
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 @_TF6switch1cFT_T_
c()
// CHECK: [[UNREACHABLE]]:
// CHECK: unreachable
}
}
struct StructPatternTest {
var x: Int
var y: String
}
// CHECK-LABEL: sil hidden @_TF6switch19test_struct_patternFT1sVS_17StructPatternTest_T_
func test_struct_pattern(s s: StructPatternTest) {
switch s {
// CHECK: [[X:%.*]] = struct_extract [[S:%.*]] : $StructPatternTest, #StructPatternTest.x
// CHECK: [[Y:%.*]] = struct_extract [[S]] : $StructPatternTest, #StructPatternTest.y
// CHECK: retain_value [[Y]]
// CHECK: cond_br {{%.*}}, [[IS_CASE1:bb[0-9]+]], [[IS_NOT_CASE1:bb[0-9]+]]
// CHECK: [[IS_CASE1]]:
// CHECK: release_value [[Y]]
// CHECK: release_value [[S]]
case StructPatternTest(x: 0):
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[IS_NOT_CASE1]]:
// CHECK: cond_br {{%.*}}, [[IS_CASE2:bb[0-9]+]], [[IS_NOT_CASE2:bb[0-9]+]]
// CHECK: [[IS_CASE2]]:
// CHECK: release_value [[Y]]
// CHECK: release_value [[S]]
case StructPatternTest(y: ""):
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_NOT_CASE2]]:
// CHECK: release_value [[Y]]
// CHECK: release_value [[S]]
case (StructPatternTest(x: _)):
// CHECK: function_ref @_TF6switch1cFT_T_
// CHECK: br [[CONT]]
c()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1dFT_T_
d()
}
struct StructPatternTestAO {
var x: Int
var y: P
}
func ~=(a: P, b: P) -> Bool { return true }
// CHECK-LABEL: sil hidden @_TF6switch22test_struct_pattern_aoFT1sVS_19StructPatternTestAO1pPS_1P__T_
func test_struct_pattern_ao(s s: StructPatternTestAO, p: P) {
// CHECK: [[S:%.*]] = alloc_stack $StructPatternTestAO
// CHECK: copy_addr %0 to [initialization] [[S]]#1
// CHECK: [[T0:%.*]] = struct_element_addr [[S]]#1 : $*StructPatternTestAO, #StructPatternTestAO.x
// CHECK: [[X:%.*]] = load [[T0]]
// CHECK: [[T0:%.*]] = struct_element_addr [[S]]#1 : $*StructPatternTestAO, #StructPatternTestAO.y
// CHECK: [[Y:%.*]] = alloc_stack $P
// CHECK: copy_addr [[T0]] to [initialization] [[Y]]#1
switch s {
// CHECK: cond_br {{%.*}}, [[IS_CASE1:bb[0-9]+]], [[IS_NOT_CASE1:bb[0-9]+]]
// CHECK: [[IS_CASE1]]:
// CHECK: destroy_addr [[Y]]#1
// CHECK: dealloc_stack [[Y]]#0
// CHECK: destroy_addr [[S]]#1
// CHECK: dealloc_stack [[S]]#0
case StructPatternTestAO(x: 0):
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[IS_NOT_CASE1]]:
// CHECK: [[TEMP:%.*]] = alloc_stack $P
// CHECK: copy_addr [[Y]]#1 to [initialization] [[TEMP]]#1
// CHECK: cond_br {{%.*}}, [[IS_CASE2:bb[0-9]+]], [[IS_NOT_CASE2:bb[0-9]+]]
// CHECK: [[IS_CASE2]]:
case StructPatternTestAO(y: p):
// CHECK: destroy_addr [[TEMP]]#1
// CHECK: dealloc_stack [[TEMP]]#0
// CHECK: destroy_addr [[Y]]#1
// CHECK: dealloc_stack [[Y]]#0
// CHECK: destroy_addr [[S]]#1
// CHECK: dealloc_stack [[S]]#0
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_NOT_CASE2]]:
// CHECK: destroy_addr [[TEMP]]#1
// CHECK: dealloc_stack [[TEMP]]#0
// CHECK: br [[IS_CASE3:bb[0-9]+]]
// CHECK: [[IS_CASE3]]:
// CHECK: destroy_addr [[Y]]#1
// CHECK: dealloc_stack [[Y]]#0
// CHECK: destroy_addr [[S]]#1
// CHECK: dealloc_stack [[S]]#0
case StructPatternTestAO(x: _):
// CHECK: function_ref @_TF6switch1cFT_T_
// CHECK: br [[CONT]]
c()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1dFT_T_
// CHECK: destroy_addr %0 : $*StructPatternTestAO
d()
}
class ClassPatternTest {
var x: Int = 0
var y: String = ""
}
// CHECK-LABEL: sil hidden @_TF6switch18test_class_patternFT1kCS_16ClassPatternTest_T_
// CHECK: bb0([[C:%.*]] : $ClassPatternTest):
func test_class_pattern(k k: ClassPatternTest) {
switch k {
// CHECK: [[XM:%.*]] = class_method [[C]] : $ClassPatternTest, #ClassPatternTest.x!getter.1
// CHECK: [[X:%.*]]= apply [[XM:%.*]]([[C]])
// CHECK: [[YM:%.*]] = class_method [[C]] : $ClassPatternTest, #ClassPatternTest.y!getter.1
// CHECK: [[Y:%.*]]= apply [[YM:%.*]]([[C]])
// CHECK: cond_br {{%.*}}, [[IS_CASE1:bb[0-9]+]], [[IS_NOT_CASE1:bb[0-9]+]]
// CHECK: [[IS_CASE1]]:
case ClassPatternTest(x: 0):
// CHECK: release_value [[Y]]
// CHECK: strong_release [[C]]
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[IS_NOT_CASE1]]:
// CHECK: cond_br {{%.*}}, [[IS_CASE2:bb[0-9]+]], [[IS_NOT_CASE2:bb[0-9]+]]
// CHECK: [[IS_CASE2]]:
case ClassPatternTest(y: ""):
// CHECK: release_value [[Y]]
// CHECK: strong_release [[C]]
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_NOT_CASE2]]:
case ClassPatternTest(x: _):
// CHECK: release_value [[Y]]
// CHECK: strong_release [[C]]
// CHECK: function_ref @_TF6switch1cFT_T_
// CHECK: br [[CONT]]
c()
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1dFT_T_
d()
}
class SubclassTestA : ClassPatternTest {}
class SubclassTestB : ClassPatternTest {}
// CHECK-LABEL: sil hidden @{{.*}}test_class_pattern_with_isa_1
// CHECK: bb0([[C:%.*]] : $ClassPatternTest):
func test_class_pattern_with_isa_1(k k: ClassPatternTest) {
switch k {
// CHECK: [[XM:%.*]] = class_method %0 : $ClassPatternTest, #ClassPatternTest.x!getter.1
// CHECK: [[X:%.*]] = apply [[XM:%.*]](%0)
// CHECK: cond_br {{%.*}}, [[IS_CASE1:bb[0-9]+]], [[IS_NOT_CASE1:bb[0-9]+]]
// CHECK: [[IS_CASE1]]:
case ClassPatternTest(x: 0):
// CHECK: strong_release [[C]]
// CHECK: function_ref @_TF6switch1aFT_T_
// CHECK: br [[CONT:bb[0-9]+]]
a()
// CHECK: [[IS_NOT_CASE1]]:
// CHECK: checked_cast_br [[C]] : $ClassPatternTest to $SubclassTestA, [[IS_A:bb[0-9]+]], [[IS_NOT_A:bb[0-9]+]]
// CHECK: [[IS_A]]([[A:%.*]] : $SubclassTestA):
case is SubclassTestA:
// CHECK: strong_release %0
// CHECK: function_ref @_TF6switch1bFT_T_
// CHECK: br [[CONT]]
b()
// CHECK: [[IS_NOT_A]]:
// CHECK: [[YM:%.*]] = class_method %0 : $ClassPatternTest, #ClassPatternTest.y!getter.1
// CHECK: [[Y:%.*]] = apply [[YM:%.*]](%0)
// CHECK: cond_br {{%.*}}, [[IS_CASE3:bb[0-9]+]], [[IS_NOT_CASE3:bb[0-9]+]]
// CHECK: [[IS_CASE3]]:
case ClassPatternTest(y: ""):
// CHECK: release_value [[Y]]
// CHECK: strong_release %0
// CHECK: function_ref @_TF6switch1cFT_T_
// CHECK: br [[CONT]]
c()
// CHECK: [[IS_NOT_CASE3]]:
// CHECK: release_value [[Y]]
// CHECK: checked_cast_br %0 : $ClassPatternTest to $SubclassTestB, [[IS_B:bb[0-9]+]], [[IS_NOT_B:bb[0-9]+]]
// CHECK: [[IS_B]]([[B:%.*]] : $SubclassTestB):
case is SubclassTestB:
// CHECK: strong_release %0
// CHECK: function_ref @_TF6switch1dFT_T_
// CHECK: br [[CONT]]
d()
// CHECK: [[IS_NOT_B]]:
// CHECK: strong_release %0
// CHECK: unreachable
}
// CHECK: [[CONT]]:
// CHECK: function_ref @_TF6switch1eFT_T_
e()
}
func test_class_pattern_with_isa_2(k k: ClassPatternTest) {
switch k {
case is SubclassTestA:
a()
case ClassPatternTest(x: 0):
b()
case is SubclassTestB:
c()
case ClassPatternTest(y: ""):
d()
}
e()
}
// <rdar://problem/14826416>
func rdar14826416<T, U>(t t: T, u: U) {
switch t {
case is Int: markUsed("Int")
case is U: markUsed("U")
case _: markUsed("other")
}
}
// CHECK-LABEL: sil hidden @_TF6switch12rdar14826416
// 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 @_TF6switch12rdar14835992
func rdar14835992<T, U>(t 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")
}
}
struct StructWithComputedProperty {
var foo: Int { return 0 }
}
// rdar://15859432
// CHECK-LABEL: sil hidden @{{.*}}StructWithComputedProperty
// CHECK: function_ref{{.*}}StructWithComputedProperty.foo.getter
func testStructWithComputedProperty(s s : StructWithComputedProperty) {
switch s {
case StructWithComputedProperty(foo: let a):
markUsed(a)
}
}
// <rdar://problem/17272985>
enum ABC { case A, B, C }
// CHECK-LABEL: sil hidden @_TF6switch18testTupleWildcardsFTOS_3ABCS0__T_
// CHECK: [[X:%.*]] = tuple_extract {{%.*}} : $(ABC, ABC), 0
// CHECK: [[Y:%.*]] = tuple_extract {{%.*}} : $(ABC, ABC), 1
// 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 @_TF6switch1aFT_T_
// 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 @_TF6switch1bFT_T_
// CHECK: [[Y_B]]:
// CHECK: function_ref @_TF6switch1cFT_T_
// 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 @_TF6switch1dFT_T_
// CHECK: [[X_NOT_C]]:
// CHECK: function_ref @_TF6switch1eFT_T_
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 @_TF6switch24testLabeledScalarPayloadFOS_20LabeledScalarPayloadP_
func testLabeledScalarPayload(lsp: LabeledScalarPayload) -> Any {
// CHECK: switch_enum {{%.*}}, case #LabeledScalarPayload.Payload!enumelt.1: bb1
switch lsp {
// CHECK: bb1([[TUPLE:%.*]] : $(name: Int)):
// CHECK: [[X:%.*]] = tuple_extract [[TUPLE]]
// CHECK: [[ANY_X_ADDR:%.*]] = init_existential_addr {{%.*}}, $Int
// CHECK: store [[X]] to [[ANY_X_ADDR]]
case let .Payload(x):
return x
}
}
// There should be no unreachable generated.
// CHECK-LABEL: sil hidden @_TF6switch19testOptionalPatternFGSqSi_T_
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 @_TF6switch19testOptionalEnumMixFGSqSi_Si
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.Int2048, 0
case .None:
return 42
// CHECK: [[NILBB]]:
// CHECK: integer_literal $Builtin.Int2048, 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 @_TF6switch26testOptionalEnumMixWithNilFGSqSi_Si
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.Int2048, 0
case nil:
return 42
// CHECK: [[NILBB]]:
// CHECK: integer_literal $Builtin.Int2048, 42
}
}