// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -module-name switch_var %s | %FileCheck %s // 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 runced(x x: Int) -> Bool { return true } func funged(x x: Int) -> Bool { return true } func ansed(x x: Int) -> Bool { return true } func foo() -> Int { return 0 } func bar() -> Int { return 0 } func foobar() -> (Int, Int) { return (0, 0) } func foos() -> String { return "" } func bars() -> String { return "" } func a() {} func b() {} func c() {} func d() {} func e() {} func f() {} func g() {} func a(x x: Int) {} func b(x x: Int) {} func c(x x: Int) {} func d(x x: Int) {} func a(x x: String) {} func b(x x: String) {} func aa(x x: (Int, Int)) {} func bb(x x: (Int, Int)) {} func cc(x x: (Int, Int)) {} // CHECK-LABEL: sil hidden [ossa] @$s10switch_var05test_B2_1yyF func test_var_1() { // CHECK: function_ref @$s10switch_var3fooSiyF switch foo() { // CHECK: [[XADDR:%.*]] = alloc_box ${ var Int } // CHECK: [[XLIFETIME:%.*]] = begin_borrow [var_decl] [[XADDR]] // CHECK: [[X:%.*]] = project_box [[XLIFETIME]] // CHECK-NOT: br bb case var x: // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[X]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var1a1xySi_tF // CHECK: destroy_value [[XADDR]] a(x: x) } // CHECK: function_ref @$s10switch_var1byyF b() } // CHECK-LABEL: sil hidden [ossa] @$s10switch_var05test_B2_2yyF func test_var_2() { // CHECK: function_ref @$s10switch_var3fooSiyF switch foo() { // CHECK: [[XADDR:%.*]] = alloc_box ${ var Int } // CHECK: [[XLIFETIME:%.*]] = begin_borrow [var_decl] [[XADDR]] // CHECK: [[X:%.*]] = project_box [[XLIFETIME]] // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[X]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var6runced1xSbSi_tF // CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]] // -- TODO: Clean up these empty waypoint bbs. case var x where runced(x: x): // CHECK: [[CASE1]]: // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[X]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var1a1xySi_tF // CHECK: destroy_value [[XADDR]] // CHECK: br [[CONT:bb[0-9]+]] a(x: x) // CHECK: [[NO_CASE1]]: // CHECK: [[YADDR:%.*]] = alloc_box ${ var Int } // CHECK: [[YLIFETIME:%.*]] = begin_borrow [var_decl] [[YADDR]] // CHECK: [[Y:%.*]] = project_box [[YLIFETIME]] // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Y]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var6funged1xSbSi_tF // CHECK: cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NO_CASE2:bb[0-9]+]] case var y where funged(x: y): // CHECK: [[CASE2]]: // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Y]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var1b1xySi_tF // CHECK: destroy_value [[YADDR]] // CHECK: br [[CONT]] b(x: y) case var z: // CHECK: [[NO_CASE2]]: // CHECK: [[ZADDR:%.*]] = alloc_box ${ var Int } // CHECK: [[ZLIFETIME:%.*]] = begin_borrow [var_decl] [[ZADDR]] // CHECK: [[Z:%.*]] = project_box [[ZLIFETIME]] // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var1c1xySi_tF // CHECK: destroy_value [[ZADDR]] // CHECK: br [[CONT]] c(x: z) } // CHECK: [[CONT]]: // CHECK: function_ref @$s10switch_var1dyyF d() } // CHECK-LABEL: sil hidden [ossa] @$s10switch_var05test_B2_3yyF func test_var_3() { // CHECK: function_ref @$s10switch_var3fooSiyF // CHECK: function_ref @$s10switch_var3barSiyF switch (foo(), bar()) { // CHECK: [[XADDR:%.*]] = alloc_box ${ var (Int, Int) } // CHECK: [[XLIFETIME:%.*]] = begin_borrow [var_decl] [[XADDR]] // CHECK: [[X:%.*]] = project_box [[XLIFETIME]] // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[X]] // CHECK: tuple_element_addr [[READ]] : {{.*}}, 0 // CHECK: function_ref @$s10switch_var6runced1xSbSi_tF // CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]] case var x where runced(x: x.0): // CHECK: [[CASE1]]: // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[X]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var2aa1xySi_Sit_tF // CHECK: destroy_value [[XADDR]] // CHECK: br [[CONT:bb[0-9]+]] aa(x: x) // CHECK: [[NO_CASE1]]: // CHECK: [[YADDR:%.*]] = alloc_box ${ var Int } // CHECK: [[YLIFETIME:%.*]] = begin_borrow [var_decl] [[YADDR]] // CHECK: [[Y:%.*]] = project_box [[YLIFETIME]] // CHECK: [[ZADDR:%.*]] = alloc_box ${ var Int } // CHECK: [[ZLIFETIME:%.*]] = begin_borrow [var_decl] [[ZADDR]] // CHECK: [[Z:%.*]] = project_box [[ZLIFETIME]] // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Y]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var6funged1xSbSi_tF // CHECK: cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NO_CASE2:bb[0-9]+]] case (var y, var z) where funged(x: y): // CHECK: [[CASE2]]: // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Y]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var1a1xySi_tF // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var1b1xySi_tF // CHECK: destroy_value [[ZADDR]] // CHECK: destroy_value [[YADDR]] // CHECK: br [[CONT]] a(x: y) b(x: z) // CHECK: [[NO_CASE2]]: // CHECK: [[WADDR:%.*]] = alloc_box ${ var (Int, Int) } // CHECK: [[WLIFETIME:%.*]] = begin_borrow [var_decl] [[WADDR]] // CHECK: [[W:%.*]] = project_box [[WLIFETIME]] // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[W]] // CHECK: tuple_element_addr [[READ]] : {{.*}}, 0 // CHECK: function_ref @$s10switch_var5ansed1xSbSi_tF // CHECK: cond_br {{%.*}}, [[CASE3:bb[0-9]+]], [[NO_CASE3:bb[0-9]+]] case var w where ansed(x: w.0): // CHECK: [[CASE3]]: // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[W]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var2bb1xySi_Sit_tF // CHECK: br [[CONT]] bb(x: w) // CHECK: [[NO_CASE3]]: // CHECK: destroy_value [[WADDR]] case var v: // CHECK: [[VADDR:%.*]] = alloc_box ${ var (Int, Int) } // CHECK: [[VLIFETIME:%.*]] = begin_borrow [var_decl] [[VADDR]] // CHECK: [[V:%.*]] = project_box [[VLIFETIME]] // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[V]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var2cc1xySi_Sit_tF // CHECK: destroy_value [[VADDR]] // CHECK: br [[CONT]] cc(x: v) } // CHECK: [[CONT]]: // CHECK: function_ref @$s10switch_var1dyyF d() } protocol P { func p() } struct X : P { func p() {} } struct Y : P { func p() {} } struct Z : P { func p() {} } // CHECK-LABEL: sil hidden [ossa] @$s10switch_var05test_B2_41pyAA1P_p_tF : $@convention(thin) (@in_guaranteed any P) -> () { func test_var_4(p p: P) { // CHECK: function_ref @$s10switch_var3fooSiyF switch (p, foo()) { // CHECK: [[PAIR:%.*]] = alloc_stack $(any P, Int) // CHECK: store // CHECK: [[PAIR_0:%.*]] = tuple_element_addr [[PAIR]] : $*(any P, Int), 0 // CHECK: [[T0:%.*]] = tuple_element_addr [[PAIR]] : $*(any P, Int), 1 // CHECK: [[PAIR_1:%.*]] = load [trivial] [[T0]] : $*Int // CHECK: [[TMP:%.*]] = alloc_stack $X // CHECK: checked_cast_addr_br copy_on_success any P in [[PAIR_0]] : $*any P to X in [[TMP]] : $*X, [[IS_X:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]] // CHECK: [[IS_X]]: // CHECK: [[T0:%.*]] = load [trivial] [[TMP]] : $*X // CHECK: [[XADDR:%.*]] = alloc_box ${ var Int } // CHECK: [[XLIFETIME:%.*]] = begin_borrow [var_decl] [[XADDR]] // CHECK: [[X:%.*]] = project_box [[XLIFETIME]] // CHECK: store [[PAIR_1]] to [trivial] [[X]] // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[X]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var6runced1xSbSi_tF // CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]] case (is X, var x) where runced(x: x): // CHECK: [[CASE1]]: // CHECK: function_ref @$s10switch_var1a1xySi_tF // CHECK: destroy_value [[XADDR]] // CHECK: dealloc_stack [[TMP]] // CHECK: destroy_addr [[PAIR_0]] : $*any P // CHECK: dealloc_stack [[PAIR]] // CHECK: br [[CONT:bb[0-9]+]] a(x: x) // CHECK: [[NO_CASE1]]: // CHECK: destroy_value [[XADDR]] // CHECK: dealloc_stack [[TMP]] // CHECK: br [[NEXT:bb[0-9]+]] // CHECK: [[IS_NOT_X]]: // CHECK: dealloc_stack [[TMP]] // CHECK: br [[NEXT]] // CHECK: [[NEXT]]: // CHECK: [[TMP:%.*]] = alloc_stack $Y // CHECK: checked_cast_addr_br copy_on_success any P in [[PAIR_0]] : $*any P to Y in [[TMP]] : $*Y, [[IS_Y:bb[0-9]+]], [[IS_NOT_Y:bb[0-9]+]] // CHECK: [[IS_Y]]: // CHECK: [[T0:%.*]] = load [trivial] [[TMP]] : $*Y // CHECK: [[YADDR:%.*]] = alloc_box ${ var Int } // CHECK: [[YLIFETIME:%.*]] = begin_borrow [var_decl] [[YADDR]] // CHECK: [[Y:%.*]] = project_box [[YLIFETIME]] // CHECK: store [[PAIR_1]] to [trivial] [[Y]] // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Y]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var6funged1xSbSi_tF // CHECK: cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NO_CASE2:bb[0-9]+]] case (is Y, var y) where funged(x: y): // CHECK: [[CASE2]]: // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Y]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var1b1xySi_tF // CHECK: destroy_value [[YADDR]] // CHECK: dealloc_stack [[TMP]] // CHECK: destroy_addr [[PAIR_0]] : $*any P // CHECK: dealloc_stack [[PAIR]] // CHECK: br [[CONT]] b(x: y) // CHECK: [[NO_CASE2]]: // CHECK: destroy_value [[YADDR]] // CHECK: dealloc_stack [[TMP]] // CHECK: br [[NEXT:bb[0-9]+]] // CHECK: [[IS_NOT_Y]]: // CHECK: dealloc_stack [[TMP]] // CHECK: br [[NEXT]] // CHECK: [[NEXT]]: // CHECK: [[ZADDR:%.*]] = alloc_box ${ var (any P, Int) } // CHECK: [[ZLIFETIME:%.+]] = begin_borrow [lexical] [var_decl] [[ZADDR]] // CHECK: [[Z:%.*]] = project_box [[ZLIFETIME]] // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] // CHECK: tuple_element_addr [[READ]] : {{.*}}, 1 // CHECK: function_ref @$s10switch_var5ansed1xSbSi_tF // CHECK: cond_br {{%.*}}, [[CASE3:bb[0-9]+]], [[DFLT_NO_CASE3:bb[0-9]+]] case var z where ansed(x: z.1): // CHECK: [[CASE3]]: // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]] // CHECK: tuple_element_addr [[READ]] : {{.*}}, 1 // CHECK: function_ref @$s10switch_var1c1xySi_tF // CHECK: end_borrow [[ZLIFETIME]] // CHECK: destroy_value [[ZADDR]] // CHECK-NEXT: destroy_addr [[PAIR]] // CHECK-NEXT: dealloc_stack [[PAIR]] // CHECK: br [[CONT]] c(x: z.1) // CHECK: [[DFLT_NO_CASE3]]: // CHECK-NEXT: end_borrow [[ZLIFETIME]] // CHECK-NEXT: destroy_value [[ZADDR]] // CHECK-NOT: destroy_addr case (_, var w): // CHECK: [[PAIR_0:%.*]] = tuple_element_addr [[PAIR]] : $*(any P, Int), 0 // CHECK: [[WADDR:%.*]] = alloc_box ${ var Int } // CHECK: [[WLIFETIME:%.*]] = begin_borrow [var_decl] [[WADDR]] // CHECK: [[W:%.*]] = project_box [[WLIFETIME]] // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[W]] // CHECK: load [trivial] [[READ]] // CHECK: function_ref @$s10switch_var1d1xySi_tF // CHECK: destroy_value [[WADDR]] // CHECK-NEXT: destroy_addr [[PAIR_0]] : $*any P // CHECK-NEXT: dealloc_stack [[PAIR]] // CHECK-NEXT: dealloc_stack // CHECK-NEXT: br [[CONT]] d(x: w) } e() } // CHECK-LABEL: sil hidden [ossa] @$s10switch_var05test_B2_5yyF : $@convention(thin) () -> () { func test_var_5() { // CHECK: function_ref @$s10switch_var3fooSiyF // CHECK: function_ref @$s10switch_var3barSiyF switch (foo(), bar()) { // CHECK: [[XADDR:%.*]] = alloc_box ${ var (Int, Int) } // CHECK: [[XLIFETIME:%.*]] = begin_borrow [var_decl] [[XADDR]] // CHECK: [[X:%.*]] = project_box [[XLIFETIME]] // CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]] case var x where runced(x: x.0): // CHECK: [[CASE1]]: // CHECK: br [[CONT:bb[0-9]+]] a() // CHECK: [[NO_CASE1]]: // CHECK: [[YADDR:%[0-9]+]] = alloc_box ${ var Int } // CHECK: [[YLIFETIME:%[0-9]+]] = begin_borrow [var_decl] [[YADDR]] // CHECK: [[Y:%[0-9]+]] = project_box [[YLIFETIME]] // CHECK: [[ZADDR:%[0-9]+]] = alloc_box ${ var Int } // CHECK: [[ZLIFETIME:%[0-9]+]] = begin_borrow [var_decl] [[ZADDR]] // CHECK: [[Z:%[0-9]+]] = project_box [[ZLIFETIME]] // CHECK: cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NO_CASE2:bb[0-9]+]] case (var y, var z) where funged(x: y): // CHECK: [[CASE2]]: // CHECK: destroy_value [[ZADDR]] // CHECK: destroy_value [[YADDR]] // CHECK: br [[CONT]] b() // CHECK: [[NO_CASE2]]: // CHECK: destroy_value [[ZADDR]] // CHECK: destroy_value [[YADDR]] // CHECK: cond_br {{%.*}}, [[CASE3:bb[0-9]+]], [[NO_CASE3:bb[0-9]+]] case (_, _) where runced(): // CHECK: [[CASE3]]: // CHECK: br [[CONT]] c() // CHECK: [[NO_CASE3]]: // CHECK: br [[CASE4:bb[0-9]+]] case _: // CHECK: [[CASE4]]: d() } e() } // CHECK-LABEL: sil hidden [ossa] @$s10switch_var05test_B7_returnyyF : $@convention(thin) () -> () { func test_var_return() { switch (foo(), bar()) { case var x where runced(): // CHECK: [[XADDR:%[0-9]+]] = alloc_box ${ var (Int, Int) } // CHECK: [[XLIFETIME:%[0-9]+]] = begin_borrow [var_decl] [[XADDR]] // CHECK: [[X:%[0-9]+]] = project_box [[XLIFETIME]] // CHECK: function_ref @$s10switch_var1ayyF // CHECK: destroy_value [[XADDR]] // CHECK: br [[EPILOG:bb[0-9]+]] a() return // CHECK: [[YADDR:%[0-9]+]] = alloc_box ${ var Int } // CHECK: [[YLIFETIME:%[0-9]+]] = begin_borrow [var_decl] [[YADDR]] // CHECK: [[Y:%[0-9]+]] = project_box [[YLIFETIME]] // CHECK: [[ZADDR:%[0-9]+]] = alloc_box ${ var Int } // CHECK: [[ZLIFETIME:%[0-9]+]] = begin_borrow [var_decl] [[ZADDR]] // CHECK: [[Z:%[0-9]+]] = project_box [[ZLIFETIME]] case (var y, var z) where funged(): // CHECK: function_ref @$s10switch_var1byyF // CHECK: destroy_value [[ZADDR]] // CHECK: destroy_value [[YADDR]] // CHECK: br [[EPILOG]] b() return case var w where ansed(): // CHECK: [[WADDR:%[0-9]+]] = alloc_box ${ var (Int, Int) } // CHECK: [[WLIFETIME:%[0-9]+]] = begin_borrow [var_decl] [[WADDR]] // CHECK: [[W:%[0-9]+]] = project_box [[WLIFETIME]] // CHECK: function_ref @$s10switch_var1cyyF // CHECK-NOT: destroy_value [[ZADDR]] // CHECK-NOT: destroy_value [[YADDR]] // CHECK: destroy_value [[WADDR]] // CHECK: br [[EPILOG]] c() return case var v: // CHECK: [[VADDR:%[0-9]+]] = alloc_box ${ var (Int, Int) } // CHECK: [[VLIFETIME:%[0-9]+]] = begin_borrow [var_decl] [[VADDR]] // CHECK: [[V:%[0-9]+]] = project_box [[VLIFETIME]] // CHECK: function_ref @$s10switch_var1dyyF // CHECK-NOT: destroy_value [[ZADDR]] // CHECK-NOT: destroy_value [[YADDR]] // CHECK: destroy_value [[VADDR]] // CHECK: br [[EPILOG]] d() return } } // When all of the bindings in a column are immutable, don't emit a mutable // box. // CHECK-LABEL: sil hidden [ossa] @$s10switch_var8test_letyyF : $@convention(thin) () -> () { func test_let() { // CHECK: [[FOOS:%.*]] = function_ref @$s10switch_var4foosSSyF // CHECK: [[VAL:%.*]] = apply [[FOOS]]() // CHECK: [[BORROWED_VAL:%.*]] = begin_borrow [[VAL]] // CHECK: [[VAL_COPY:%.*]] = copy_value [[BORROWED_VAL]] // CHECK: [[VAL_MOVE:%.*]] = move_value [var_decl] [[VAL_COPY]] // CHECK: function_ref @$s10switch_var6runcedSbyF // CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]] switch foos() { case let x where runced(): // CHECK: [[CASE1]]: // CHECK: [[VAL_BORROW:%.*]] = begin_borrow [[VAL_MOVE]] // CHECK: [[A:%.*]] = function_ref @$s10switch_var1a1xySS_tF // CHECK: apply [[A]]([[VAL_BORROW]]) // CHECK: end_borrow [[VAL_BORROW]] // CHECK: destroy_value [[VAL_MOVE]] // CHECK: destroy_value [[VAL]] // CHECK: br [[CONT:bb[0-9]+]] a(x: x) // CHECK: [[NO_CASE1]]: // CHECK: destroy_value [[VAL_MOVE]] // CHECK: [[BORROWED_VAL_2:%.*]] = begin_borrow [[VAL]] // CHECK: [[VAL_COPY_2:%.*]] = copy_value [[BORROWED_VAL_2]] // CHECK: [[VAL_MOVE_2:%.*]] = move_value [var_decl] [[VAL_COPY_2]] // CHECK: function_ref @$s10switch_var6fungedSbyF // CHECK: cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NO_CASE2:bb[0-9]+]] case let y where funged(): // CHECK: [[CASE2]]: // CHECK: [[BORROWED_VAL_MOVE_2:%.*]] = begin_borrow [[VAL_MOVE_2]] // CHECK: [[B:%.*]] = function_ref @$s10switch_var1b1xySS_tF // CHECK: apply [[B]]([[BORROWED_VAL_MOVE_2]]) // CHECK: destroy_value [[VAL_MOVE_2]] // CHECK: destroy_value [[VAL]] // CHECK: br [[CONT]] b(x: y) // CHECK: [[NO_CASE2]]: // CHECK: destroy_value [[VAL_MOVE_2]] // CHECK: [[BORROWED_VAL_3:%.*]] = begin_borrow [[VAL]] // CHECK: [[VAL_COPY_3:%.*]] = copy_value [[BORROWED_VAL_3]] // CHECK: [[VAL_MOVE_3:%.*]] = move_value [var_decl] [[VAL_COPY_3]] // CHECK: function_ref @$s10switch_var4barsSSyF // CHECK: [[BORROWED_VAL_MOVE_3:%.*]] = begin_borrow [[VAL_MOVE_3]] // CHECK: [[SB:%.*]] = store_borrow [[BORROWED_VAL_MOVE_3]] to [[IN_ARG:%.*]] : // CHECK: apply {{%.*}}({{.*}}, [[SB]]) // CHECK: cond_br {{%.*}}, [[YES_CASE3:bb[0-9]+]], [[NO_CASE3:bb[0-9]+]] // ExprPatterns implicitly contain a 'let' binding. case bars(): // CHECK: [[YES_CASE3]]: // CHECK: destroy_value [[VAL_MOVE_3]] // CHECK: [[FUNC:%.*]] = function_ref @$s10switch_var1cyyF // CHECK-NEXT: apply [[FUNC]]( // CHECK: destroy_value [[VAL]] // CHECK: br [[CONT]] c() case _: // CHECK: [[NO_CASE3]]: // CHECK: destroy_value [[VAL_MOVE_3]] // CHECK: function_ref @$s10switch_var1dyyF // CHECK: destroy_value [[VAL]] // CHECK: br [[CONT]] d() } // CHECK: [[CONT]]: // CHECK: return } // CHECK: } // end sil function '$s10switch_var8test_letyyF' // If one of the bindings is a "var", allocate a box for the column. // CHECK-LABEL: sil hidden [ossa] @$s10switch_var015test_mixed_let_B0yyF : $@convention(thin) () -> () { func test_mixed_let_var() { // CHECK: bb0: // CHECK: [[FOOS:%.*]] = function_ref @$s10switch_var4foosSSyF // CHECK: [[VAL:%.*]] = apply [[FOOS]]() // CHECK: [[BORROWED_VAL:%.*]] = begin_borrow [[VAL]] switch foos() { // First pattern. // CHECK: [[BOX:%.*]] = alloc_box ${ var String }, var, name "x" // CHECK: [[PLIFETIME:%.*]] = begin_borrow [var_decl] [[BOX]] // CHECK: [[PBOX:%.*]] = project_box [[PLIFETIME]] // CHECK: [[VAL_COPY:%.*]] = copy_value [[BORROWED_VAL]] // CHECK: store [[VAL_COPY]] to [init] [[PBOX]] // CHECK: cond_br {{.*}}, [[CASE1:bb[0-9]+]], [[NOCASE1:bb[0-9]+]] case var x where runced(): // CHECK: [[CASE1]]: // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[PBOX]] // CHECK: [[X:%.*]] = load [copy] [[READ]] // CHECK: [[A:%.*]] = function_ref @$s10switch_var1a1xySS_tF // CHECK: apply [[A]]([[X]]) // CHECK: destroy_value [[BOX]] // CHECK: br [[CONT:bb[0-9]+]] a(x: x) // CHECK: [[NOCASE1]]: // CHECK: destroy_value [[BOX]] // CHECK: [[BORROWED_VAL:%.*]] = begin_borrow [[VAL]] // CHECK: [[VAL_COPY:%.*]] = copy_value [[BORROWED_VAL]] // CHECK: [[VAL_MOVE:%.*]] = move_value [var_decl] [[VAL_COPY]] // CHECK: cond_br {{.*}}, [[CASE2:bb[0-9]+]], [[NOCASE2:bb[0-9]+]] case let y where funged(): // CHECK: [[CASE2]]: // CHECK: [[BORROWED_VAL_MOVE:%.*]] = begin_borrow [[VAL_MOVE]] // CHECK: [[B:%.*]] = function_ref @$s10switch_var1b1xySS_tF // CHECK: apply [[B]]([[BORROWED_VAL_MOVE]]) // CHECK: end_borrow [[BORROWED_VAL_MOVE]] // CHECK: destroy_value [[VAL_MOVE]] // CHECK: destroy_value [[VAL]] // CHECK: br [[CONT]] b(x: y) // CHECK: [[NOCASE2]]: // CHECK: destroy_value [[VAL_MOVE]] // CHECK: [[BORROWED_VAL:%.*]] = begin_borrow [[VAL]] // CHECK: [[VAL_COPY:%.*]] = copy_value [[BORROWED_VAL]] // CHECK: [[VAL_MOVE:%.*]] = move_value [var_decl] [[VAL_COPY]] // CHECK: [[BORROWED_VAL_MOVE:%.*]] = begin_borrow [[VAL_MOVE]] // CHECK: [[SB:%.*]] = store_borrow [[BORROWED_VAL_MOVE]] to [[TMP_VAL_COPY_ADDR:%.*]] : // CHECK: apply {{.*}}({{.*}}, [[SB]]) // CHECK: cond_br {{.*}}, [[CASE3:bb[0-9]+]], [[NOCASE3:bb[0-9]+]] case bars(): // CHECK: [[CASE3]]: // CHECK: destroy_value [[VAL_MOVE]] // CHECK: [[FUNC:%.*]] = function_ref @$s10switch_var1cyyF : $@convention(thin) () -> () // CHECK: apply [[FUNC]]() // CHECK: destroy_value [[VAL]] // CHECK: br [[CONT]] c() // CHECK: [[NOCASE3]]: // CHECK: destroy_value [[VAL_MOVE]] // CHECK: [[D_FUNC:%.*]] = function_ref @$s10switch_var1dyyF : $@convention(thin) () -> () // CHECK: apply [[D_FUNC]]() // CHECK: destroy_value [[VAL]] // CHECK: br [[CONT]] case _: d() } // CHECK: [[CONT]]: // CHECK: return } // CHECK: } // end sil function '$s10switch_var015test_mixed_let_B0yyF' // CHECK-LABEL: sil hidden [ossa] @$s10switch_var23test_multiple_patterns1yyF : $@convention(thin) () -> () { func test_multiple_patterns1() { // CHECK: function_ref @$s10switch_var6foobarSi_SityF switch foobar() { // CHECK-NOT: br bb case (0, let x), (let x, 0): // CHECK: cond_br {{%.*}}, [[FIRST_MATCH_CASE:bb[0-9]+]], [[FIRST_FAIL:bb[0-9]+]] // CHECK: [[FIRST_MATCH_CASE]]: // CHECK: br [[CASE_BODY:bb[0-9]+]]([[FIRST_X:%.*]] : $Int) // CHECK: [[FIRST_FAIL]]: // CHECK: cond_br {{%.*}}, [[SECOND_MATCH_CASE:bb[0-9]+]], [[SECOND_FAIL:bb[0-9]+]] // CHECK: [[SECOND_MATCH_CASE]]: // CHECK: br [[CASE_BODY]]([[SECOND_X:%.*]] : $Int) // CHECK: [[CASE_BODY]]([[BODY_VAR:%.*]] : $Int): // CHECK: debug_value [[BODY_VAR]] : $Int, let, name "x" // CHECK: [[A:%.*]] = function_ref @$s10switch_var1a1xySi_tF // CHECK: apply [[A]]([[BODY_VAR]]) a(x: x) default: // CHECK: [[SECOND_FAIL]]: // CHECK: function_ref @$s10switch_var1byyF b() } } // FIXME: The extend_lifetime is the local variable's cleanup. It should occur after all uses of the local. Instead, it // is emitted before the branch to the switch case body. // // CHECK-LABEL: sil hidden [ossa] @$s10switch_var23test_multiple_patterns2yyF : $@convention(thin) () -> () { func test_multiple_patterns2() { let t1 = 2 let t2 = 4 // CHECK: debug_value [[T1:%.+]] : // CHECK: debug_value [[T2:%.+]] : switch (0,0) { // CHECK-NOT: br bb case (_, let x) where x > t1, (let x, _) where x > t2: // CHECK: ([[FIRST:%[0-9]+]], [[SECOND:%[0-9]+]]) = destructure_tuple {{%.+}} : $(Int, Int) // CHECK: [[MV_SECOND:%.*]] = move_value [var_decl] [[SECOND]] : $Int // CHECK: apply {{%.+}}([[MV_SECOND]], [[T1]], {{%.+}}) // CHECK: cond_br {{%.*}}, [[FIRST_MATCH_CASE:bb[0-9]+]], [[FIRST_FAIL:bb[0-9]+]] // CHECK: [[FIRST_MATCH_CASE]]: // CHECK: extend_lifetime [[MV_SECOND]] : $Int // CHECK: br [[CASE_BODY:bb[0-9]+]]([[MV_SECOND]] : $Int) // CHECK: [[FIRST_FAIL]]: // CHECK: [[MV_FIRST:%.*]] = move_value [var_decl] %21 : $Int // CHECK: apply {{%.*}}([[MV_FIRST]], [[T2]], {{%.+}}) // CHECK: cond_br {{%.*}}, [[SECOND_MATCH_CASE:bb[0-9]+]], [[SECOND_FAIL:bb[0-9]+]] // CHECK: [[SECOND_MATCH_CASE]]: // CHECK: br [[CASE_BODY]]([[MV_FIRST]] : $Int) // CHECK: [[CASE_BODY]]([[BODY_VAR:%.*]] : $Int): // CHECK: [[A:%.*]] = function_ref @$s10switch_var1a1xySi_tF // CHECK: apply [[A]]([[BODY_VAR]]) a(x: x) default: // CHECK: [[SECOND_FAIL]]: // CHECK: function_ref @$s10switch_var1byyF b() } } enum Foo { case A(Int, Double) case B(Double, Int) case C(Int, Int, Double) } // FIXME: The extend_lifetime is the local variable's cleanup. It should occur after all uses of the local. Instead, it // is emitted before the branch to the switch case body. // // CHECK-LABEL: sil hidden [ossa] @$s10switch_var23test_multiple_patterns3yyF : $@convention(thin) () -> () { func test_multiple_patterns3() { let f = Foo.C(0, 1, 2.0) switch f { // CHECK: switch_enum {{%.*}} : $Foo, case #Foo.A!enumelt: [[A:bb[0-9]+]], case #Foo.B!enumelt: [[B:bb[0-9]+]], case #Foo.C!enumelt: [[C:bb[0-9]+]] case .A(let x, let n), .B(let n, let x), .C(_, let x, let n): // CHECK: [[A]]([[A_TUP:%.*]] : $(Int, Double)): // CHECK: ([[A_X:%.*]], [[A_N:%.*]]) = destructure_tuple [[A_TUP]] // CHECK: [[MV_A_X:%.*]] = move_value [var_decl] [[A_X]] : $Int // CHECK: [[MV_A_N:%.*]] = move_value [var_decl] [[A_N]] : $Double // CHECK: extend_lifetime [[MV_A_N]] : $Double // CHECK: extend_lifetime [[MV_A_X]] : $Int // CHECK: br [[CASE_BODY:bb[0-9]+]]([[MV_A_X]] : $Int, [[MV_A_N]] : $Double) // CHECK: [[B]]([[B_TUP:%.*]] : $(Double, Int)): // CHECK: ([[B_N:%.*]], [[B_X:%.*]]) = destructure_tuple [[B_TUP]] // CHECK: [[MV_B_N:%.*]] = move_value [var_decl] [[B_N]] : $Double // CHECK: [[MV_B_X:%.*]] = move_value [var_decl] [[B_X]] : $Int // CHECK: br [[CASE_BODY]]([[MV_B_X]] : $Int, [[MV_B_N]] : $Double) // CHECK: [[C]]([[C_TUP:%.*]] : $(Int, Int, Double)): // CHECK: ([[C__:%.*]], [[C_X:%.*]], [[C_N:%.*]]) = destructure_tuple [[C_TUP]] // CHECK: [[MV_C_X:%.*]] = move_value [var_decl] [[C_X]] : $Int // CHECK: [[MV_C_N:%.*]] = move_value [var_decl] [[C_N]] : $Double // CHECK: br [[CASE_BODY]]([[MV_C_X]] : $Int, [[MV_C_N]] : $Double) // CHECK: [[CASE_BODY]]([[BODY_X:%.*]] : $Int, [[BODY_N:%.*]] : $Double): // CHECK: [[FUNC_A:%.*]] = function_ref @$s10switch_var1a1xySi_tF // CHECK: apply [[FUNC_A]]([[BODY_X]]) a(x: x) } } enum Bar { case Y(Foo, Int) case Z(Int, Foo) } // CHECK-LABEL: sil hidden [ossa] @$s10switch_var23test_multiple_patterns4yyF : $@convention(thin) () -> () { func test_multiple_patterns4() { let b = Bar.Y(.C(0, 1, 2.0), 3) switch b { // CHECK: switch_enum {{%.*}} : $Bar, case #Bar.Y!enumelt: [[Y:bb[0-9]+]], case #Bar.Z!enumelt: [[Z:bb[0-9]+]] case .Y(.A(let x, _), _), .Y(.B(_, let x), _), .Y(.C, let x), .Z(let x, _): // CHECK: [[Y]]([[Y_TUP:%.*]] : $(Foo, Int)): // CHECK: ([[Y_F:%.*]], [[Y_X:%.*]]) = destructure_tuple [[Y_TUP]] // CHECK: switch_enum [[Y_F]] : $Foo, case #Foo.A!enumelt: [[A:bb[0-9]+]], case #Foo.B!enumelt: [[B:bb[0-9]+]], case #Foo.C!enumelt: [[C:bb[0-9]+]] // CHECK: [[A]]([[A_TUP:%.*]] : $(Int, Double)): // CHECK: ([[A_X:%.*]], [[A_N:%.*]]) = destructure_tuple [[A_TUP]] // CHECK: [[MV_A:%.*]] = move_value [var_decl] %30 : $Int // CHECK: br [[CASE_BODY:bb[0-9]+]]([[MV_A]] : $Int) // CHECK: [[B]]([[B_TUP:%.*]] : $(Double, Int)): // CHECK: ([[B_N:%.*]], [[B_X:%.*]]) = destructure_tuple [[B_TUP]] // CHECK: [[MV_B_X:%.*]] = move_value [var_decl] [[B_X]] : $Int // CHECK: br [[CASE_BODY]]([[MV_B_X]] : $Int) // CHECK: [[C]]({{%.*}} : $(Int, Int, Double)): // CHECK: [[MV_Y_X:%.*]] = move_value [var_decl] [[Y_X]] : $Int // CHECK: br [[CASE_BODY]]([[MV_Y_X]] : $Int) // CHECK: [[Z]]([[Z_TUP:%.*]] : $(Int, Foo)): // CHECK: ([[Z_X:%.*]], [[Z_F:%.*]]) = destructure_tuple [[Z_TUP]] // CHECK: [[MV_Z_X:%.*]] = move_value [var_decl] [[Z_X]] : $Int // CHECK: br [[CASE_BODY]]([[MV_Z_X]] : $Int) // CHECK: [[CASE_BODY]]([[BODY_X:%.*]] : $Int): // CHECK: [[FUNC_A:%.*]] = function_ref @$s10switch_var1a1xySi_tF // CHECK: apply [[FUNC_A]]([[BODY_X]]) a(x: x) } } func aaa(x x: inout Int) {} // CHECK-LABEL: sil hidden [ossa] @$s10switch_var23test_multiple_patterns5yyF : $@convention(thin) () -> () { func test_multiple_patterns5() { let b = Bar.Y(.C(0, 1, 2.0), 3) switch b { // CHECK: switch_enum {{%.*}} : $Bar, case #Bar.Y!enumelt: [[Y:bb[0-9]+]], case #Bar.Z!enumelt: [[Z:bb[0-9]+]] case .Y(.A(var x, _), _), .Y(.B(_, var x), _), .Y(.C, var x), .Z(var x, _): // CHECK: [[Y]]([[Y_TUP:%.*]] : $(Foo, Int)): // CHECK: ([[Y_F:%.*]], [[Y_X:%.*]]) = destructure_tuple [[Y_TUP]] // CHECK: switch_enum [[Y_F]] : $Foo, case #Foo.A!enumelt: [[A:bb[0-9]+]], case #Foo.B!enumelt: [[B:bb[0-9]+]], case #Foo.C!enumelt: [[C:bb[0-9]+]] // CHECK: [[A]]([[A_TUP:%.*]] : $(Int, Double)): // CHECK: ([[A_X:%.*]], [[A_N:%.*]]) = destructure_tuple [[A_TUP]] // CHECK: [[MV_X:%.*]] = move_value [var_decl] [[A_X]] : $Int // CHECK: br [[CASE_BODY:bb[0-9]+]]([[MV_X]] : $Int) // CHECK: [[B]]([[B_TUP:%.*]] : $(Double, Int)): // CHECK: ([[B_N:%.*]], [[B_X:%.*]]) = destructure_tuple [[B_TUP]] // CHECK: [[MV_B_X:%.*]] = move_value [var_decl] [[B_X]] : $Int // CHECK: br [[CASE_BODY]]([[MV_B_X]] : $Int) // CHECK: [[C]]({{%.*}} : $(Int, Int, Double)): // CHECK: [[MV_Y_X:%.*]] = move_value [var_decl] [[Y_X]] : $Int // CHECK: br [[CASE_BODY]]([[MV_Y_X]] : $Int) // CHECK: [[Z]]([[Z_TUP:%.*]] : $(Int, Foo)): // CHECK: ([[Z_X:%.*]], [[Z_F:%.*]]) = destructure_tuple [[Z_TUP]] // CHECK: [[MV_Z_X:%.*]] = move_value [var_decl] [[Z_X]] : $Int // CHECK: br [[CASE_BODY]]([[MV_Z_X]] : $Int) // CHECK: [[CASE_BODY]]([[BODY_X:%.*]] : $Int): // CHECK: store [[BODY_X]] to [trivial] [[BOX_X:%.*]] : $*Int // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[BOX_X]] // CHECK: [[FUNC_AAA:%.*]] = function_ref @$s10switch_var3aaa1xySiz_tF // CHECK: apply [[FUNC_AAA]]([[WRITE]]) aaa(x: &x) } } // rdar://problem/29252758 -- local decls must not be reemitted. func test_against_reemission(x: Bar) { switch x { case .Y(let a, _), .Z(_, let a): let b = a } } class C {} class D: C {} func f(_: D) -> Bool { return true } // CHECK-LABEL: sil hidden [ossa] @{{.*}}test_multiple_patterns_value_semantics func test_multiple_patterns_value_semantics(_ y: C) { switch y { // CHECK: checked_cast_br C in {{%.*}} : $C to D, [[AS_D:bb[0-9]+]], [[NOT_AS_D:bb[0-9]+]] // CHECK: [[AS_D]]({{.*}}): // CHECK: [[ORIG_MOVE:%.*]] = move_value [lexical] [var_decl] [[ORIG:%.*]] : // CHECK: [[ORIG_BORROW:%.*]] = begin_borrow [[ORIG_MOVE:%.*]] : // CHECK: cond_br {{%.*}}, [[F_TRUE:bb[0-9]+]], [[F_FALSE:bb[0-9]+]] // CHECK: [[F_TRUE]]: // CHECK: [[BINDING:%.*]] = copy_value [[ORIG_MOVE]] : // CHECK: destroy_value [[ORIG_MOVE]] // CHECK: br {{bb[0-9]+}}([[BINDING]] case let x as D where f(x), let x as D: break default: break } }