// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -module-name switch %s | %FileCheck %s ////////////////// // Declarations // ////////////////// func markUsed(_ t: T) {} // TODO: Implement tuple equality in the library. // BLOCKED: 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() {} func a(_ k: Klass) {} func b(_ k: Klass) {} func c(_ k: Klass) {} func d(_ k: Klass) {} func e(_ k: Klass) {} func f(_ k: Klass) {} func g(_ k: Klass) {} class Klass { var isTrue: Bool { return true } var isFalse: Bool { return false } } enum TrivialSingleCaseEnum { case a } enum NonTrivialSingleCaseEnum { case a(Klass) } enum MultipleNonTrivialCaseEnum { case a(Klass) case b(Klass) case c(Klass) } enum MultipleAddressOnlyCaseEnum { case a(T) case b(T) case c(T) } /////////// // Tests // /////////// // 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 $any P // CHECK-NEXT: copy_addr %0 to [init] [[PTMPBUF]] : $*any P switch p { // CHECK: [[TMPBUF:%[0-9]+]] = alloc_stack $X // CHECK: checked_cast_addr_br copy_on_success any P in [[P:%.*]] : $*any 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 any P in [[P]] : $*any 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 any P in [[P]] : $*any 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 any P in [[P:%.*]] : $*any 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 any P in [[P]] : $*any 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 any P in [[P:%.*]] : $*any 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 any P in [[P]] : $*any 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 B in [[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: br [[CONT:bb[0-9]+]] a() // CHECK: [[NO_CASE1]]: // CHECK-NEXT: destroy_value [[CAST_D1_COPY]] // CHECK: br [[NEXT_CASE:bb[0-9]+]] // CHECK: [[IS_NOT_D1]]([[CASTFAIL_D1:%.*]] : @guaranteed $B): // CHECK-NEXT: br [[NEXT_CASE]] // CHECK: [[NEXT_CASE]]: // CHECK: checked_cast_br B in [[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: checked_cast_br B in [[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: br [[NEXT_CASE:bb[0-9]+]] // CHECK: [[IS_NOT_E]]([[NOTCAST_E:%.*]] : @guaranteed $B): // CHECK: br [[NEXT_CASE]] // CHECK: [[NEXT_CASE]]: // CHECK: checked_cast_br B in [[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: br [[CONT]] d() // CHECK: [[IS_NOT_C]]([[NOCAST_C:%.*]] : @guaranteed $B): 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 B in [[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: [[MOVED_D1_COPY:%.*]] = move_value [lexical] [var_decl] [[CAST_D1_COPY]] // 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 [[MOVED_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 [[MOVED_D1_COPY]] // CHECK: br [[CONT:bb[0-9]+]]([[RET]] : $AnyObject) a() return y // CHECK: [[NO_CASE1]]: // CHECK: destroy_value [[MOVED_D1_COPY]] // CHECK: br [[NEXT_CASE:bb5]] // CHECK: [[IS_NOT_D1]]([[NOCAST_D1:%.*]] : @guaranteed $B): // CHECK: br [[NEXT_CASE]] // CHECK: [[NEXT_CASE]]: // CHECK: checked_cast_br B in [[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: [[MOVED_CAST_D2_COPY:%.*]] = move_value [lexical] [var_decl] [[CAST_D2_COPY]] // CHECK: function_ref @$s6switch1byyF // CHECK: [[BORROWED_CAST_D2_COPY:%.*]] = begin_borrow [[MOVED_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 [[MOVED_CAST_D2_COPY]] // CHECK: br [[CONT]]([[RET]] : $AnyObject) b() return y // CHECK: [[IS_NOT_D2]]([[NOCAST_D2:%.*]] : @guaranteed $B): // CHECK: checked_cast_br B in [[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: [[MOVED_CAST_E_COPY:%.*]] = move_value [lexical] [var_decl] [[CAST_E_COPY]] // 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 [[MOVED_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 [[MOVED_CAST_E_COPY]] // CHECK: br [[CONT]]([[RET]] : $AnyObject) c() return y // CHECK: [[NO_CASE3]]: // CHECK: destroy_value [[MOVED_CAST_E_COPY]] // CHECK: br [[NEXT_CASE:bb[0-9]+]] // CHECK: [[IS_NOT_E]]([[NOCAST_E:%.*]] : @guaranteed $B): // CHECK: br [[NEXT_CASE]] // CHECK: [[NEXT_CASE]] // CHECK: checked_cast_br B in [[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: [[MOVED_CAST_C_COPY:%.*]] = move_value [lexical] [var_decl] [[CAST_C_COPY]] // CHECK: function_ref @$s6switch1dyyF // CHECK: [[BORROWED_CAST_C_COPY:%.*]] = begin_borrow [[MOVED_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 [[MOVED_CAST_C_COPY]] // CHECK: br [[CONT]]([[RET]] : $AnyObject) d() return y // CHECK: [[IS_NOT_C]]([[NOCAST_C:%.*]] : @guaranteed $B): 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' // https://github.com/apple/swift/issues/56139 // CHECK-LABEL: sil hidden [ossa] @$s6switch31test_isa_pattern_array_downcast2psySayAA1P_pG_tF : $@convention(thin) (@guaranteed Array) -> () { func test_isa_pattern_array_downcast(ps: Array

) { // CHECK: bb0(%0 : @guaranteed $Array): switch ps { // CHECK: checked_cast_addr_br copy_on_success Array in [[P:%[0-9]+]] : $*Array to Array in {{%[0-9]+}} : $*Array, [[IS_X:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]] case is [X]: // CHECK: [[IS_X]]: // CHECK: function_ref @$s6switch1ayyF a() // CHECK: br [[CONT:bb[0-9]+]] // CHECK: [[IS_NOT_X]]: // CHECK: [[DEST:%[0-9]+]] = alloc_stack $Array // CHECK-NEXT: checked_cast_addr_br copy_on_success Array in [[P:%[0-9]+]] : $*Array to Array in [[DEST]] : $*Array, [[IS_Y:bb[0-9]+]], [[IS_NOT_Y:bb[0-9]+]] case let _ as [Y]: // CHECK: [[IS_Y]]: // CHECK-NEXT: load [take] [[DEST]] : $*Array // CHECK: function_ref @$s6switch1byyF b() // CHECK: br [[CONT]] default: // CHECK: [[IS_NOT_Y]]: // CHECK: function_ref @$s6switch1cyyF c() // CHECK: br [[CONT]] } // CHECK: [[CONT]]: // CHECK: function_ref @$s6switch1dyyF d() } // CHECK: } // end sil function '$s6switch31test_isa_pattern_array_downcast2psySayAA1P_pG_tF' // CHECK-LABEL: sil hidden [ossa] @$s6switch39test_isa_pattern_array_downcast_closureyyF : $@convention(thin) () -> () { // CHECK: function_ref @$s6switch39test_isa_pattern_array_downcast_closureyyFySayAA1P_pGcfU_ // CHECK: } // end sil function '$s6switch39test_isa_pattern_array_downcast_closureyyF' func test_isa_pattern_array_downcast_closure() { // CHECK-LABEL: sil private [ossa] @$s6switch39test_isa_pattern_array_downcast_closureyyFySayAA1P_pGcfU_ : $@convention(thin) (@guaranteed Array) -> () { let _ = { (ps: [P]) -> Void in // CHECK: bb0(%0 : @guaranteed $Array): switch ps { // CHECK: [[DEST:%[0-9]+]] = alloc_stack $Array // CHECK-NEXT: checked_cast_addr_br copy_on_success Array in [[P:%[0-9]+]] : $*Array to Array in [[DEST]] : $*Array, [[IS_X:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]] case let _ as [X]: // CHECK: [[IS_X]]: // CHECK-NEXT: load [take] [[DEST]] : $*Array // CHECK: function_ref @$s6switch1ayyF a() // CHECK: br [[CONT:bb[0-9]+]] // CHECK: [[IS_NOT_X]]: // CHECK: br [[DEF:bb[0-9]+]] default: // CHECK: [[DEF]]: // CHECK: function_ref @$s6switch1byyF b() // CHECK: br [[CONT]] } } // CHECK: } // end sil function '$s6switch39test_isa_pattern_array_downcast_closureyyFySayAA1P_pGcfU_' } // CHECK-LABEL: sil hidden [ossa] @$s6switch30test_isa_pattern_dict_downcast2psySDySSAA1P_pG_tF : $@convention(thin) (@guaranteed Dictionary) -> () { func test_isa_pattern_dict_downcast(ps: Dictionary) { // CHECK: bb0(%0 : @guaranteed $Dictionary): switch ps { // CHECK: checked_cast_addr_br copy_on_success Dictionary in [[P:%[0-9]+]] : $*Dictionary to Dictionary in {{%[0-9]+}} : $*Dictionary, [[IS_X:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]] case is [String : X]: // CHECK: [[IS_X]]: // CHECK: function_ref @$s6switch1ayyF a() // CHECK: br [[CONT:bb[0-9]+]] // CHECK: [[IS_NOT_X]]: // CHECK: [[DEST:%[0-9]+]] = alloc_stack $Dictionary // CHECK-NEXT: checked_cast_addr_br copy_on_success Dictionary in [[P:%[0-9]+]] : $*Dictionary to Dictionary in [[DEST]] : $*Dictionary, [[IS_Y:bb[0-9]+]], [[IS_NOT_Y:bb[0-9]+]] case let _ as [String : Y]: // CHECK: [[IS_Y]]: // CHECK-NEXT: load [take] [[DEST]] : $*Dictionary // CHECK: function_ref @$s6switch1byyF b() // CHECK: br [[CONT]] default: // CHECK: [[IS_NOT_Y]]: // CHECK: function_ref @$s6switch1cyyF c() // CHECK: br [[CONT]] } // CHECK: [[CONT]]: // CHECK: function_ref @$s6switch1dyyF d() } // CHECK-LABEL: } // end sil function '$s6switch30test_isa_pattern_dict_downcast2psySDySSAA1P_pG_tF' // CHECK-LABEL: sil hidden [ossa] @$s6switch29test_isa_pattern_set_downcast2psyShyxG_tSHRzlF : $@convention(thin) (@guaranteed Set) -> () { func test_isa_pattern_set_downcast(ps: Set) { // CHECK: bb0(%0 : @guaranteed $Set): switch ps { // CHECK: checked_cast_addr_br copy_on_success Set in [[P:%[0-9]+]] : $*Set to Set in {{%[0-9]+}} : $*Set, [[IS_INT:bb[0-9]+]], [[IS_NOT_INT:bb[0-9]+]] case is Set: // CHECK: [[IS_INT]]: // CHECK: function_ref @$s6switch1ayyF a() // CHECK: br [[CONT:bb[0-9]+]] // CHECK: [[IS_NOT_INT]]: // CHECK: [[DEST:%[0-9]+]] = alloc_stack $Set // CHECK-NEXT: checked_cast_addr_br copy_on_success Set in [[P:%[0-9]+]] : $*Set to Set in [[DEST]] : $*Set, [[IS_BOOL:bb[0-9]+]], [[IS_NOT_BOOL:bb[0-9]+]] case let _ as Set: // CHECK: [[IS_BOOL]]: // CHECK-NEXT: load [take] [[DEST]] : $*Set // CHECK: function_ref @$s6switch1byyF b() // CHECK: br [[CONT]] default: // CHECK: [[IS_NOT_BOOL]]: // CHECK: function_ref @$s6switch1cyyF c() // CHECK: br [[CONT]] } // CHECK: [[CONT]]: // CHECK: function_ref @$s6switch1dyyF d() } // CHECK: } // end sil function '$s6switch29test_isa_pattern_set_downcast2psyShyxG_tSHRzlF' 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: [[IS_LEFT:bb[0-9]+]], // CHECK: case #MaybePair.Right!enumelt: [[IS_RIGHT:bb[0-9]+]], // CHECK: case #MaybePair.Both!enumelt: [[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: [[IS_LEFT:bb[0-9]+]], // CHECK: case #MaybePair.Right!enumelt: [[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: [[IS_LEFT:bb[0-9]+]], // CHECK: case #MaybePair.Right!enumelt: [[IS_RIGHT:bb[0-9]+]], // CHECK: case #MaybePair.Both!enumelt: [[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: [[IS_LEFT:bb[0-9]+]], // CHECK: case #MaybePair.Right!enumelt: [[IS_RIGHT:bb[0-9]+]], // CHECK: case #MaybePair.Both!enumelt: [[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: [[IS_LEFT:bb[0-9]+]], // CHECK: case #MaybeAddressOnlyPair.Right!enumelt: [[IS_RIGHT:bb[0-9]+]], // CHECK: case #MaybeAddressOnlyPair.Both!enumelt: [[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 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 // 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 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 { case Foo(T) case Bar(U) } // Check that switching over a generic instance generates verified SIL. func test_union_generic_instance(u: Generic) { 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 } } // func rdar14826416(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]+]] // class Rdar14835992 {} class SubRdar14835992 : Rdar14835992 {} // CHECK-LABEL: sil hidden [ossa] @$s6switch12rdar14835992{{[_0-9a-zA-Z]*}}F func rdar14835992(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") } } // 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: bb1 switch lsp { // CHECK: bb1([[TUPLE:%.*]] : $(name: Int)): // CHECK: [[X:%.*]] = destructure_tuple [[TUPLE]] // CHECK: [[MV:%.*]] = move_value [var_decl] [[X]] : $Int // CHECK: [[ANY_X_ADDR:%.*]] = init_existential_addr {{%.*}}, $Int // CHECK: store [[MV]] 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, case #Optional.some!enumelt: 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, let, name "a" // CHECK-NEXT: switch_enum %0 : $Optional, case #Optional.some!enumelt: [[SOMEBB:bb[0-9]+]], case #Optional.none!enumelt: [[NILBB:bb[0-9]+]] switch a { case let x?: return 0 // CHECK: [[SOMEBB]]([[X:%.*]] : $Int): // CHECK-NEXT: [[MV:%.*]] = move_value [var_decl] [[X]] : $Int // CHECK-NEXT: debug_value [[MV]] : $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, let, name "a" // CHECK-NEXT: switch_enum %0 : $Optional, case #Optional.some!enumelt: [[SOMEBB:bb[0-9]+]], case #Optional.none!enumelt: [[NILBB:bb[0-9]+]] switch a { case let x?: return 0 // CHECK: [[SOMEBB]]([[X:%.*]] : $Int): // CHECK-NEXT: [[MV:%.*]] = move_value [var_decl] [[X]] : $Int // CHECK-NEXT: debug_value [[MV]] : $Int, let, name "x" // CHECK: integer_literal $Builtin.IntLiteral, 0 case nil: return 42 // CHECK: [[NILBB]]: // CHECK: integer_literal $Builtin.IntLiteral, 42 } } // https://github.com/apple/swift/issues/46106 // // CHECK-LABEL: sil hidden [ossa] @$s6switch43testMultiPatternsWithOuterScopeSameNamedVar4base6filterySiSg_AEtF func testMultiPatternsWithOuterScopeSameNamedVar(base: Int?, filter: Int?) { switch(base, filter) { case (.some(let base), .some(let filter)): // CHECK: bb1([[BASE:%[0-9]+]] : $Int): // CHECK: switch_enum // CHECK: bb2([[FILTER:%[0-9]+]] : $Int): // CHECK-NEXT: [[MV_BASE:%.*]] = move_value [var_decl] [[BASE]] // CHECK-NEXT: [[MV_FILTER:%.*]] = move_value [var_decl] [[FILTER]] // CHECK-NEXT: debug_value [[MV_BASE]] : $Int, let, name "base" // CHECK-NEXT: debug_value [[MV_FILTER]] : $Int, let, name "filter" print("both: \(base), \(filter)") case (.some(let base), .none), (.none, .some(let base)): // CHECK: bb3: // CHECK-NEXT: [[MV_BASE_PATTERN:%.*]] = move_value [var_decl] [[BASE]] : $Int // CHECK-NEXT: extend_lifetime [[MV_BASE_PATTERN]] : $Int // CHECK-NEXT: br bb6([[MV_BASE_PATTERN]] : $Int) // CHECK: bb5([[OTHER_BASE:%.*]] : $Int) // CHECK-NEXT: [[MV_OTHER_BASE:%.*]] = move_value [var_decl] [[OTHER_BASE]] : $Int // CHECK-NEXT: extend_lifetime [[MV_OTHER_BASE]] : $Int // CHECK-NEXT: br bb6([[MV_OTHER_BASE]] : $Int) // CHECK: bb6([[ARG:%.*]] : $Int): // CHECK-NEXT: debug_value [[ARG]] : $Int, let, name "base" 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: ignored_use %1 // CHECK-NEXT: unreachable switch myFatalError() {} } } // Make sure that we properly can handle address only tuples with loadable // subtypes. // 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 [init] [[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 [init] [[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: 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) -> () { // CHECK: bb0([[ARG0:%.*]] : @guaranteed $Klass, [[ARG1:%.*]] : $*Optional): // CHECK: [[ARG0_COPY:%.*]] = copy_value [[ARG0]] // CHECK: [[ARG1_COPY:%.*]] = alloc_stack $Optional // CHECK: copy_addr [[ARG1]] to [init] [[ARG1_COPY]] // CHECK: [[TUP:%.*]] = alloc_stack $(Klass, Optional) // CHECK: [[TUP_0:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 0 // CHECK: [[TUP_1:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 1 // CHECK: store [[ARG0_COPY]] to [init] [[TUP_0]] // CHECK: copy_addr [take] [[ARG1_COPY]] to [init] [[TUP_1]] // CHECK: [[TUP_0:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 0 // CHECK: [[TUP_0_VAL:%.*]] = load_borrow [[TUP_0]] // CHECK: [[TUP_1:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 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) -> () { // CHECK: bb0([[ARG0:%.*]] : @guaranteed $Klass, [[ARG1:%.*]] : $*Optional): // CHECK: [[ARG0_COPY:%.*]] = copy_value [[ARG0]] // CHECK: [[ARG1_COPY:%.*]] = alloc_stack $Optional // CHECK: copy_addr [[ARG1]] to [init] [[ARG1_COPY]] // CHECK: [[TUP:%.*]] = alloc_stack $(Klass, Optional) // CHECK: [[TUP_0:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 0 // CHECK: [[TUP_1:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 1 // CHECK: store [[ARG0_COPY]] to [init] [[TUP_0]] // CHECK: copy_addr [take] [[ARG1_COPY]] to [init] [[TUP_1]] // CHECK: [[TUP_0:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 0 // CHECK: [[TUP_0_VAL:%.*]] = load_borrow [[TUP_0]] // CHECK: [[TUP_1:%.*]] = tuple_element_addr [[TUP]] : $*(Klass, Optional), 1 // CHECK: checked_cast_br Klass in [[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, case #Optional.some!enumelt: [[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 // CHECK-NEXT: copy_addr [[TUP_1]] to [init] [[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: [[MOVED:%.*]] = move_value // CHECK-NEXT: debug_value // CHECK-NEXT: destroy_value [[MOVED]] // 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 // https://github.com/apple/swift/issues/49213. Just make sure that we still // pass the ownership verifier. // // `indirect` is necessary; generic parameter is necessary. indirect enum IndirectGenericEnum { // 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 } } //////////////////////////////////////////////// // Fallthrough Multiple Case Label Item Tests // //////////////////////////////////////////////// // CHECK-LABEL: sil hidden [ossa] @$s6switch28addressOnlyFallthroughCalleeyyAA015MultipleAddressC8CaseEnumOyxGSzRzlF : $@convention(thin) (@in_guaranteed MultipleAddressOnlyCaseEnum) -> () { // CHECK: bb0([[ARG:%.*]] : // CHECK: [[AB_PHI:%.*]] = alloc_stack $T // CHECK: [[ABB_PHI:%.*]] = alloc_stack $T // CHECK: [[ABBC_PHI:%.*]] = alloc_stack $T // CHECK: [[SWITCH_ENUM_ARG:%.*]] = alloc_stack $MultipleAddressOnlyCaseEnum // CHECK: copy_addr [[ARG]] to [init] [[SWITCH_ENUM_ARG]] // CHECK: switch_enum_addr [[SWITCH_ENUM_ARG]] : $*MultipleAddressOnlyCaseEnum, case #MultipleAddressOnlyCaseEnum.a!enumelt: [[BB_A:bb[0-9]+]], case #MultipleAddressOnlyCaseEnum.b!enumelt: [[BB_B:bb[0-9]+]], case #MultipleAddressOnlyCaseEnum.c!enumelt: [[BB_C:bb[0-9]+]] // // CHECK: [[BB_A]]: // CHECK: [[SWITCH_ENUM_ARG_PROJ:%.*]] = unchecked_take_enum_data_addr [[SWITCH_ENUM_ARG]] // CHECK: [[CASE_BODY_VAR_A:%.*]] = alloc_stack [lexical] [var_decl] $T, let, name "x" // CHECK: copy_addr [take] [[SWITCH_ENUM_ARG_PROJ]] to [init] [[CASE_BODY_VAR_A]] // CHECK: copy_addr [[CASE_BODY_VAR_A]] to [init] [[AB_PHI]] // CHECK: destroy_addr [[CASE_BODY_VAR_A]] // CHECK: br [[BB_AB:bb[0-9]+]] // // CHECK: [[BB_B]]: // CHECK: [[SWITCH_ENUM_ARG_PROJ:%.*]] = unchecked_take_enum_data_addr [[SWITCH_ENUM_ARG]] // CHECK: [[CASE_BODY_VAR_B:%.*]] = alloc_stack [lexical] [var_decl] $T, let, name "x" // CHECK: copy_addr [[SWITCH_ENUM_ARG_PROJ]] to [init] [[CASE_BODY_VAR_B]] // CHECK: [[FUNC_CMP:%.*]] = function_ref @$sSzsE2eeoiySbx_qd__tSzRd__lFZ : // CHECK: [[GUARD_RESULT:%.*]] = apply [[FUNC_CMP]]([[CASE_BODY_VAR_B]], {{%.*}}, {{%.*}}) // CHECK: [[GUARD_RESULT_EXT:%.*]] = struct_extract [[GUARD_RESULT]] // CHECK: cond_br [[GUARD_RESULT_EXT]], [[BB_B_GUARD_SUCC:bb[0-9]+]], [[BB_B_GUARD_FAIL:bb[0-9]+]] // // CHECK: [[BB_B_GUARD_SUCC]]: // CHECK: copy_addr [[CASE_BODY_VAR_B]] to [init] [[AB_PHI]] // CHECK: destroy_addr [[CASE_BODY_VAR_B]] // CHECK: destroy_addr [[SWITCH_ENUM_ARG_PROJ]] // CHECK: br [[BB_AB]] // // CHECK: [[BB_AB]]: // CHECK: copy_addr [[AB_PHI]] to [init] [[ABB_PHI]] // CHECK: destroy_addr [[AB_PHI]] // CHECK: br [[BB_AB_CONT:bb[0-9]+]] // // CHECK: [[BB_AB_CONT]]: // CHECK: copy_addr [[ABB_PHI]] to [init] [[ABBC_PHI]] // CHECK: destroy_addr [[ABB_PHI]] // CHECK: br [[BB_FINAL_CONT:bb[0-9]+]] // // CHECK: [[BB_B_GUARD_FAIL]]: // CHECK: destroy_addr [[CASE_BODY_VAR_B]] // CHECK: [[CASE_BODY_VAR_B_2:%.*]] = alloc_stack [lexical] [var_decl] $T, let, name "x" // CHECK: copy_addr [take] [[SWITCH_ENUM_ARG_PROJ]] to [init] [[CASE_BODY_VAR_B_2]] // CHECK: copy_addr [[CASE_BODY_VAR_B_2]] to [init] [[ABB_PHI]] // CHECK: br [[BB_AB_CONT]] // // CHECK: [[BB_C]]: // CHECK: [[SWITCH_ENUM_ARG_PROJ:%.*]] = unchecked_take_enum_data_addr [[SWITCH_ENUM_ARG]] // CHECK: [[CASE_BODY_VAR_C:%.*]] = alloc_stack [lexical] [var_decl] $T, let, name "x" // CHECK: copy_addr [take] [[SWITCH_ENUM_ARG_PROJ]] to [init] [[CASE_BODY_VAR_C]] // CHECK: copy_addr [[CASE_BODY_VAR_C]] to [init] [[ABBC_PHI]] // CHECK: destroy_addr [[CASE_BODY_VAR_C]] // CHECK: br [[BB_FINAL_CONT]] // // CHECK: [[BB_FINAL_CONT]]: // CHECK: destroy_addr [[ABBC_PHI]] // CHECK: return // CHECK: } // end sil function '$s6switch28addressOnlyFallthroughCalleeyyAA015MultipleAddressC8CaseEnumOyxGSzRzlF' func addressOnlyFallthroughCallee(_ e : MultipleAddressOnlyCaseEnum) { switch e { case .a(let x): fallthrough case .b(let x) where x == 2: fallthrough case .b(let x): fallthrough case .c(let x): print(x) } } func addressOnlyFallthroughCaller() { var myFoo : MultipleAddressOnlyCaseEnum = MultipleAddressOnlyCaseEnum.a(10) addressOnlyFallthroughCallee(myFoo) } // CHECK-LABEL: sil hidden [ossa] @$s6switch35nonTrivialLoadableFallthroughCalleeyyAA011MultipleNonC8CaseEnumOF : $@convention(thin) (@guaranteed MultipleNonTrivialCaseEnum) -> () { // CHECK: bb0([[ARG:%.*]] : @guaranteed $MultipleNonTrivialCaseEnum): // CHECK: switch_enum [[ARG]] : $MultipleNonTrivialCaseEnum, case #MultipleNonTrivialCaseEnum.a!enumelt: [[BB_A:bb[0-9]+]], case #MultipleNonTrivialCaseEnum.b!enumelt: [[BB_B:bb[0-9]+]], case #MultipleNonTrivialCaseEnum.c!enumelt: [[BB_C:bb[0-9]+]] // // CHECK: [[BB_A]]([[BB_A_ARG:%.*]] : @guaranteed // CHECK: [[BB_A_ARG_COPY:%.*]] = copy_value [[BB_A_ARG]] // CHECK: [[BB_A_ARG_COPY_MOVE:%.*]] = move_value [lexical] [var_decl] [[BB_A_ARG_COPY]] // CHECK: [[BB_A_ARG_COPY_BORROW:%.*]] = begin_borrow [[BB_A_ARG_COPY_MOVE]] // CHECK: apply {{%.*}}([[BB_A_ARG_COPY_BORROW]]) // CHECK: [[RESULT:%.*]] = copy_value [[BB_A_ARG_COPY_MOVE]] // CHECK: br [[BB_AB:bb[0-9]+]]([[RESULT]] : // // CHECK: [[BB_B]]([[BB_B_ARG:%.*]] : @guaranteed // CHECK: [[BB_B_ARG_COPY:%.*]] = copy_value [[BB_B_ARG]] // CHECK: [[BB_B_ARG_COPY_MOVE:%.*]] = move_value [lexical] [var_decl] [[BB_B_ARG_COPY]] // CHECK: [[RESULT:%.*]] = copy_value [[BB_B_ARG_COPY_MOVE]] // CHECK: br [[BB_AB:bb[0-9]+]]([[RESULT]] : // // CHECK: [[BB_AB:bb[0-9]+]]([[BB_AB_PHI:%.*]] : @owned // CHECK: [[BB_AB_PHI_BORROW:%.*]] = begin_borrow [[BB_AB_PHI]] // CHECK: apply {{%.*}}([[BB_AB_PHI_BORROW]]) // CHECK: [[RESULT:%.*]] = copy_value [[BB_AB_PHI]] // CHECK: br [[BB_ABC:bb[0-9]+]]([[RESULT]] : // // CHECK: [[BB_C]]([[BB_C_ARG:%.*]] : @guaranteed // CHECK: [[BB_C_COPY:%.*]] = copy_value [[BB_C_ARG]] // CHECK: [[BB_C_BORROWED_MOVE:%.*]] = move_value [lexical] [var_decl] [[BB_C_COPY]] // CHECK: [[RESULT:%.*]] = copy_value [[BB_C_BORROWED_MOVE]] // CHECK: br [[BB_ABC]]([[RESULT]] : // // CHECK: [[BB_ABC]]([[BB_ABC_ARG:%.*]] : @owned // CHECK: [[BB_ABC_ARG_BORROW:%.*]] = begin_borrow [[BB_ABC_ARG]] // CHECK: apply {{%.*}}([[BB_ABC_ARG_BORROW]]) // CHECK: return // CHECK: } // end sil function '$s6switch35nonTrivialLoadableFallthroughCalleeyyAA011MultipleNonC8CaseEnumOF' func nonTrivialLoadableFallthroughCallee(_ e : MultipleNonTrivialCaseEnum) { switch e { case .a(let x): a(x) fallthrough case .b(let x): b(x) fallthrough case .c(let x): c(x) } } // Just make sure that we do not crash on this. func nonTrivialLoadableFallthroughCalleeGuards(_ e : MultipleNonTrivialCaseEnum) { switch e { case .a(let x) where x.isFalse: a(x) fallthrough case .a(let x) where x.isTrue: a(x) fallthrough case .b(let x) where x.isTrue: b(x) fallthrough case .b(let x) where x.isFalse: b(x) fallthrough case .c(let x) where x.isTrue: c(x) fallthrough case .c(let x) where x.isFalse: c(x) break default: d() } } func nonTrivialLoadableFallthroughCallee2(_ e : MultipleNonTrivialCaseEnum) { switch e { case .a(let x): a(x) fallthrough case .b(let x): b(x) break default: break } } // Make sure that we do not crash while emitting this code. // // DISCUSSION: The original crash was due to us performing an assignment/lookup // on the VarLocs DenseMap in the same statement. This was caught be an // asanified compiler. This test is just to make sure we do not regress. enum Storage { case empty case single(Int) case pair(Int, Int) case array([Int]) subscript(range: [Int]) -> Storage { get { return .empty } set { switch self { case .empty: break case .single(let index): break case .pair(let first, let second): switch (range[0], range[1]) { case (0, 0): switch newValue { case .empty: break case .single(let other): break case .pair(let otherFirst, let otherSecond): break case .array(let other): break } break case (0, 1): switch newValue { case .empty: break case .single(let other): break case .pair(let otherFirst, let otherSecond): break case .array(let other): break } break case (0, 2): break case (1, 2): switch newValue { case .empty: break case .single(let other): break case .pair(let otherFirst, let otherSecond): break case .array(let other): self = .array([first] + other) } break case (2, 2): switch newValue { case .empty: break case .single(let other): break case .pair(let otherFirst, let otherSecond): break case .array(let other): self = .array([first, second] + other) } break default: let r = range } case .array(let indexes): break } } } } // Make sure that we do not leak tuple elements if we fail to match the first // tuple element. enum rdar49990484Enum1 { case case1(Klass) case case2(Klass, Int) } enum rdar49990484Enum2 { case case1(Klass) case case2(rdar49990484Enum1, Klass) } struct rdar49990484Struct { var value: rdar49990484Enum2 func doSomethingIfLet() { if case let .case2(.case2(k, _), _) = value { return } } func doSomethingSwitch() { switch value { case let .case2(.case2(k, _), _): return default: return } return } func doSomethingGuardLet() { guard case let .case2(.case2(k, _), _) = value else { return } } }