| author | |
| committer | |
| log | ed2a5081e1f379cf089f7700a2818db35faadc05 |
| tree | db42e8cdfddcd712d7f3f01fd4bcd015f9a20d6d |
| parent | dfb3231959bb340d260ddbec2b8eabfb5063c1bf |
4 files changed, 267 insertions(+), 234 deletions(-)
src/codegen/llvm.zig+43-11| ... | @@ -1993,23 +1993,55 @@ pub const FuncGen = struct { | ... | @@ -1993,23 +1993,55 @@ pub const FuncGen = struct { |
| 1993 | 1993 | ||
| 1994 | const then_block = self.context.appendBasicBlock(self.llvm_func, "Then"); | 1994 | const then_block = self.context.appendBasicBlock(self.llvm_func, "Then"); |
| 1995 | const else_block = self.context.appendBasicBlock(self.llvm_func, "Else"); | 1995 | const else_block = self.context.appendBasicBlock(self.llvm_func, "Else"); |
| 1996 | { | 1996 | _ = self.builder.buildCondBr(cond, then_block, else_block); |
| 1997 | const prev_block = self.builder.getInsertBlock(); | ||
| 1998 | defer self.builder.positionBuilderAtEnd(prev_block); | ||
| 1999 | 1997 | ||
| 2000 | self.builder.positionBuilderAtEnd(then_block); | 1998 | self.builder.positionBuilderAtEnd(then_block); |
| 2001 | try self.genBody(then_body); | 1999 | try self.genBody(then_body); |
| 2002 | 2000 | ||
| 2003 | self.builder.positionBuilderAtEnd(else_block); | 2001 | self.builder.positionBuilderAtEnd(else_block); |
| 2004 | try self.genBody(else_body); | 2002 | try self.genBody(else_body); |
| 2005 | } | 2003 | |
| 2006 | _ = self.builder.buildCondBr(cond, then_block, else_block); | 2004 | // No need to reset the insert cursor since this instruction is noreturn. |
| 2007 | return null; | 2005 | return null; |
| 2008 | } | 2006 | } |
| 2009 | 2007 | ||
| 2010 | fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 2008 | fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 2011 | _ = inst; | 2009 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 2012 | return self.todo("implement llvm codegen for switch_br", .{}); | 2010 | const cond = try self.resolveInst(pl_op.operand); |
| 2011 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); | ||
| 2012 | const else_block = self.context.appendBasicBlock(self.llvm_func, "Else"); | ||
| 2013 | const llvm_switch = self.builder.buildSwitch(cond, else_block, switch_br.data.cases_len); | ||
| 2014 | |||
| 2015 | var extra_index: usize = switch_br.end; | ||
| 2016 | var case_i: u32 = 0; | ||
| 2017 | |||
| 2018 | while (case_i < switch_br.data.cases_len) : (case_i += 1) { | ||
| 2019 | const case = self.air.extraData(Air.SwitchBr.Case, extra_index); | ||
| 2020 | const items = @bitCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]); | ||
| 2021 | const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; | ||
| 2022 | extra_index = case.end + case.data.items_len + case_body.len; | ||
| 2023 | |||
| 2024 | const case_block = self.context.appendBasicBlock(self.llvm_func, "Case"); | ||
| 2025 | |||
| 2026 | for (items) |item| { | ||
| 2027 | const llvm_item = try self.resolveInst(item); | ||
| 2028 | llvm_switch.addCase(llvm_item, case_block); | ||
| 2029 | } | ||
| 2030 | |||
| 2031 | self.builder.positionBuilderAtEnd(case_block); | ||
| 2032 | try self.genBody(case_body); | ||
| 2033 | } | ||
| 2034 | |||
| 2035 | self.builder.positionBuilderAtEnd(else_block); | ||
| 2036 | const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; | ||
| 2037 | if (else_body.len != 0) { | ||
| 2038 | try self.genBody(else_body); | ||
| 2039 | } else { | ||
| 2040 | _ = self.builder.buildUnreachable(); | ||
| 2041 | } | ||
| 2042 | |||
| 2043 | // No need to reset the insert cursor since this instruction is noreturn. | ||
| 2044 | return null; | ||
| 2013 | } | 2045 | } |
| 2014 | 2046 | ||
| 2015 | fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 2047 | fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
src/codegen/llvm/bindings.zig+6| ... | @@ -178,6 +178,9 @@ pub const Value = opaque { | ... | @@ -178,6 +178,9 @@ pub const Value = opaque { |
| 178 | 178 | ||
| 179 | pub const setInitializer = LLVMSetInitializer; | 179 | pub const setInitializer = LLVMSetInitializer; |
| 180 | extern fn LLVMSetInitializer(GlobalVar: *const Value, ConstantVal: *const Value) void; | 180 | extern fn LLVMSetInitializer(GlobalVar: *const Value, ConstantVal: *const Value) void; |
| 181 | |||
| 182 | pub const addCase = LLVMAddCase; | ||
| 183 | extern fn LLVMAddCase(Switch: *const Value, OnVal: *const Value, Dest: *const BasicBlock) void; | ||
| 181 | }; | 184 | }; |
| 182 | 185 | ||
| 183 | pub const Type = opaque { | 186 | pub const Type = opaque { |
| ... | @@ -554,6 +557,9 @@ pub const Builder = opaque { | ... | @@ -554,6 +557,9 @@ pub const Builder = opaque { |
| 554 | pub const buildCondBr = LLVMBuildCondBr; | 557 | pub const buildCondBr = LLVMBuildCondBr; |
| 555 | extern fn LLVMBuildCondBr(*const Builder, If: *const Value, Then: *const BasicBlock, Else: *const BasicBlock) *const Value; | 558 | extern fn LLVMBuildCondBr(*const Builder, If: *const Value, Then: *const BasicBlock, Else: *const BasicBlock) *const Value; |
| 556 | 559 | ||
| 560 | pub const buildSwitch = LLVMBuildSwitch; | ||
| 561 | extern fn LLVMBuildSwitch(*const Builder, V: *const Value, Else: *const BasicBlock, NumCases: c_uint) *const Value; | ||
| 562 | |||
| 557 | pub const buildPhi = LLVMBuildPhi; | 563 | pub const buildPhi = LLVMBuildPhi; |
| 558 | extern fn LLVMBuildPhi(*const Builder, Ty: *const Type, Name: [*:0]const u8) *const Value; | 564 | extern fn LLVMBuildPhi(*const Builder, Ty: *const Type, Name: [*:0]const u8) *const Value; |
| 559 | 565 |
test/behavior/switch.zig+217| ... | @@ -2,3 +2,220 @@ const std = @import("std"); | ... | @@ -2,3 +2,220 @@ const std = @import("std"); |
| 2 | const expect = std.testing.expect; | 2 | const expect = std.testing.expect; |
| 3 | const expectError = std.testing.expectError; | 3 | const expectError = std.testing.expectError; |
| 4 | const expectEqual = std.testing.expectEqual; | 4 | const expectEqual = std.testing.expectEqual; |
| 5 | |||
| 6 | test "switch with numbers" { | ||
| 7 | try testSwitchWithNumbers(13); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testSwitchWithNumbers(x: u32) !void { | ||
| 11 | const result = switch (x) { | ||
| 12 | 1, 2, 3, 4...8 => false, | ||
| 13 | 13 => true, | ||
| 14 | else => false, | ||
| 15 | }; | ||
| 16 | try expect(result); | ||
| 17 | } | ||
| 18 | |||
| 19 | test "switch with all ranges" { | ||
| 20 | try expect(testSwitchWithAllRanges(50, 3) == 1); | ||
| 21 | try expect(testSwitchWithAllRanges(101, 0) == 2); | ||
| 22 | try expect(testSwitchWithAllRanges(300, 5) == 3); | ||
| 23 | try expect(testSwitchWithAllRanges(301, 6) == 6); | ||
| 24 | } | ||
| 25 | |||
| 26 | fn testSwitchWithAllRanges(x: u32, y: u32) u32 { | ||
| 27 | return switch (x) { | ||
| 28 | 0...100 => 1, | ||
| 29 | 101...200 => 2, | ||
| 30 | 201...300 => 3, | ||
| 31 | else => y, | ||
| 32 | }; | ||
| 33 | } | ||
| 34 | |||
| 35 | test "implicit comptime switch" { | ||
| 36 | const x = 3 + 4; | ||
| 37 | const result = switch (x) { | ||
| 38 | 3 => 10, | ||
| 39 | 4 => 11, | ||
| 40 | 5, 6 => 12, | ||
| 41 | 7, 8 => 13, | ||
| 42 | else => 14, | ||
| 43 | }; | ||
| 44 | |||
| 45 | comptime { | ||
| 46 | try expect(result + 1 == 14); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | test "switch on enum" { | ||
| 51 | const fruit = Fruit.Orange; | ||
| 52 | nonConstSwitchOnEnum(fruit); | ||
| 53 | } | ||
| 54 | const Fruit = enum { | ||
| 55 | Apple, | ||
| 56 | Orange, | ||
| 57 | Banana, | ||
| 58 | }; | ||
| 59 | fn nonConstSwitchOnEnum(fruit: Fruit) void { | ||
| 60 | switch (fruit) { | ||
| 61 | Fruit.Apple => unreachable, | ||
| 62 | Fruit.Orange => {}, | ||
| 63 | Fruit.Banana => unreachable, | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | test "switch statement" { | ||
| 68 | try nonConstSwitch(SwitchStatementFoo.C); | ||
| 69 | } | ||
| 70 | fn nonConstSwitch(foo: SwitchStatementFoo) !void { | ||
| 71 | const val = switch (foo) { | ||
| 72 | SwitchStatementFoo.A => @as(i32, 1), | ||
| 73 | SwitchStatementFoo.B => 2, | ||
| 74 | SwitchStatementFoo.C => 3, | ||
| 75 | SwitchStatementFoo.D => 4, | ||
| 76 | }; | ||
| 77 | try expect(val == 3); | ||
| 78 | } | ||
| 79 | const SwitchStatementFoo = enum { A, B, C, D }; | ||
| 80 | |||
| 81 | test "switch with multiple expressions" { | ||
| 82 | const x = switch (returnsFive()) { | ||
| 83 | 1, 2, 3 => 1, | ||
| 84 | 4, 5, 6 => 2, | ||
| 85 | else => @as(i32, 3), | ||
| 86 | }; | ||
| 87 | try expect(x == 2); | ||
| 88 | } | ||
| 89 | fn returnsFive() i32 { | ||
| 90 | return 5; | ||
| 91 | } | ||
| 92 | |||
| 93 | const Number = union(enum) { | ||
| 94 | One: u64, | ||
| 95 | Two: u8, | ||
| 96 | Three: f32, | ||
| 97 | }; | ||
| 98 | |||
| 99 | const number = Number{ .Three = 1.23 }; | ||
| 100 | |||
| 101 | fn returnsFalse() bool { | ||
| 102 | switch (number) { | ||
| 103 | Number.One => |x| return x > 1234, | ||
| 104 | Number.Two => |x| return x == 'a', | ||
| 105 | Number.Three => |x| return x > 12.34, | ||
| 106 | } | ||
| 107 | } | ||
| 108 | test "switch on const enum with var" { | ||
| 109 | try expect(!returnsFalse()); | ||
| 110 | } | ||
| 111 | |||
| 112 | test "switch on type" { | ||
| 113 | try expect(trueIfBoolFalseOtherwise(bool)); | ||
| 114 | try expect(!trueIfBoolFalseOtherwise(i32)); | ||
| 115 | } | ||
| 116 | |||
| 117 | fn trueIfBoolFalseOtherwise(comptime T: type) bool { | ||
| 118 | return switch (T) { | ||
| 119 | bool => true, | ||
| 120 | else => false, | ||
| 121 | }; | ||
| 122 | } | ||
| 123 | |||
| 124 | test "switching on booleans" { | ||
| 125 | try testSwitchOnBools(); | ||
| 126 | comptime try testSwitchOnBools(); | ||
| 127 | } | ||
| 128 | |||
| 129 | fn testSwitchOnBools() !void { | ||
| 130 | try expect(testSwitchOnBoolsTrueAndFalse(true) == false); | ||
| 131 | try expect(testSwitchOnBoolsTrueAndFalse(false) == true); | ||
| 132 | |||
| 133 | try expect(testSwitchOnBoolsTrueWithElse(true) == false); | ||
| 134 | try expect(testSwitchOnBoolsTrueWithElse(false) == true); | ||
| 135 | |||
| 136 | try expect(testSwitchOnBoolsFalseWithElse(true) == false); | ||
| 137 | try expect(testSwitchOnBoolsFalseWithElse(false) == true); | ||
| 138 | } | ||
| 139 | |||
| 140 | fn testSwitchOnBoolsTrueAndFalse(x: bool) bool { | ||
| 141 | return switch (x) { | ||
| 142 | true => false, | ||
| 143 | false => true, | ||
| 144 | }; | ||
| 145 | } | ||
| 146 | |||
| 147 | fn testSwitchOnBoolsTrueWithElse(x: bool) bool { | ||
| 148 | return switch (x) { | ||
| 149 | true => false, | ||
| 150 | else => true, | ||
| 151 | }; | ||
| 152 | } | ||
| 153 | |||
| 154 | fn testSwitchOnBoolsFalseWithElse(x: bool) bool { | ||
| 155 | return switch (x) { | ||
| 156 | false => true, | ||
| 157 | else => false, | ||
| 158 | }; | ||
| 159 | } | ||
| 160 | |||
| 161 | test "u0" { | ||
| 162 | var val: u0 = 0; | ||
| 163 | switch (val) { | ||
| 164 | 0 => try expect(val == 0), | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | test "undefined.u0" { | ||
| 169 | var val: u0 = undefined; | ||
| 170 | switch (val) { | ||
| 171 | 0 => try expect(val == 0), | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | test "switch with disjoint range" { | ||
| 176 | var q: u8 = 0; | ||
| 177 | switch (q) { | ||
| 178 | 0...125 => {}, | ||
| 179 | 127...255 => {}, | ||
| 180 | 126...126 => {}, | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | test "switch variable for range and multiple prongs" { | ||
| 185 | const S = struct { | ||
| 186 | fn doTheTest() !void { | ||
| 187 | var u: u8 = 16; | ||
| 188 | try doTheSwitch(u); | ||
| 189 | comptime try doTheSwitch(u); | ||
| 190 | var v: u8 = 42; | ||
| 191 | try doTheSwitch(v); | ||
| 192 | comptime try doTheSwitch(v); | ||
| 193 | } | ||
| 194 | fn doTheSwitch(q: u8) !void { | ||
| 195 | switch (q) { | ||
| 196 | 0...40 => |x| try expect(x == 16), | ||
| 197 | 41, 42, 43 => |x| try expect(x == 42), | ||
| 198 | else => try expect(false), | ||
| 199 | } | ||
| 200 | } | ||
| 201 | }; | ||
| 202 | _ = S; | ||
| 203 | } | ||
| 204 | |||
| 205 | var state: u32 = 0; | ||
| 206 | fn poll() void { | ||
| 207 | switch (state) { | ||
| 208 | 0 => { | ||
| 209 | state = 1; | ||
| 210 | }, | ||
| 211 | else => { | ||
| 212 | state += 1; | ||
| 213 | }, | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | test "switch on global mutable var isn't constant-folded" { | ||
| 218 | while (state < 2) { | ||
| 219 | poll(); | ||
| 220 | } | ||
| 221 | } |
test/behavior/switch_stage1.zig+1-223| ... | @@ -3,86 +3,6 @@ const expect = std.testing.expect; | ... | @@ -3,86 +3,6 @@ const expect = std.testing.expect; |
| 3 | const expectError = std.testing.expectError; | 3 | const expectError = std.testing.expectError; |
| 4 | const expectEqual = std.testing.expectEqual; | 4 | const expectEqual = std.testing.expectEqual; |
| 5 | 5 | ||
| 6 | test "switch with numbers" { | ||
| 7 | try testSwitchWithNumbers(13); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testSwitchWithNumbers(x: u32) !void { | ||
| 11 | const result = switch (x) { | ||
| 12 | 1, 2, 3, 4...8 => false, | ||
| 13 | 13 => true, | ||
| 14 | else => false, | ||
| 15 | }; | ||
| 16 | try expect(result); | ||
| 17 | } | ||
| 18 | |||
| 19 | test "switch with all ranges" { | ||
| 20 | try expect(testSwitchWithAllRanges(50, 3) == 1); | ||
| 21 | try expect(testSwitchWithAllRanges(101, 0) == 2); | ||
| 22 | try expect(testSwitchWithAllRanges(300, 5) == 3); | ||
| 23 | try expect(testSwitchWithAllRanges(301, 6) == 6); | ||
| 24 | } | ||
| 25 | |||
| 26 | fn testSwitchWithAllRanges(x: u32, y: u32) u32 { | ||
| 27 | return switch (x) { | ||
| 28 | 0...100 => 1, | ||
| 29 | 101...200 => 2, | ||
| 30 | 201...300 => 3, | ||
| 31 | else => y, | ||
| 32 | }; | ||
| 33 | } | ||
| 34 | |||
| 35 | test "implicit comptime switch" { | ||
| 36 | const x = 3 + 4; | ||
| 37 | const result = switch (x) { | ||
| 38 | 3 => 10, | ||
| 39 | 4 => 11, | ||
| 40 | 5, 6 => 12, | ||
| 41 | 7, 8 => 13, | ||
| 42 | else => 14, | ||
| 43 | }; | ||
| 44 | |||
| 45 | comptime { | ||
| 46 | try expect(result + 1 == 14); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | test "switch on enum" { | ||
| 51 | const fruit = Fruit.Orange; | ||
| 52 | nonConstSwitchOnEnum(fruit); | ||
| 53 | } | ||
| 54 | const Fruit = enum { | ||
| 55 | Apple, | ||
| 56 | Orange, | ||
| 57 | Banana, | ||
| 58 | }; | ||
| 59 | fn nonConstSwitchOnEnum(fruit: Fruit) void { | ||
| 60 | switch (fruit) { | ||
| 61 | Fruit.Apple => unreachable, | ||
| 62 | Fruit.Orange => {}, | ||
| 63 | Fruit.Banana => unreachable, | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | test "switch statement" { | ||
| 68 | try nonConstSwitch(SwitchStatementFoo.C); | ||
| 69 | } | ||
| 70 | fn nonConstSwitch(foo: SwitchStatementFoo) !void { | ||
| 71 | const val = switch (foo) { | ||
| 72 | SwitchStatementFoo.A => @as(i32, 1), | ||
| 73 | SwitchStatementFoo.B => 2, | ||
| 74 | SwitchStatementFoo.C => 3, | ||
| 75 | SwitchStatementFoo.D => 4, | ||
| 76 | }; | ||
| 77 | try expect(val == 3); | ||
| 78 | } | ||
| 79 | const SwitchStatementFoo = enum { | ||
| 80 | A, | ||
| 81 | B, | ||
| 82 | C, | ||
| 83 | D, | ||
| 84 | }; | ||
| 85 | |||
| 86 | test "switch prong with variable" { | 6 | test "switch prong with variable" { |
| 87 | try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 }); | 7 | try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 }); |
| 88 | try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 }); | 8 | try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 }); |
| ... | @@ -125,49 +45,6 @@ fn testSwitchEnumPtrCapture() !void { | ... | @@ -125,49 +45,6 @@ fn testSwitchEnumPtrCapture() !void { |
| 125 | } | 45 | } |
| 126 | } | 46 | } |
| 127 | 47 | ||
| 128 | test "switch with multiple expressions" { | ||
| 129 | const x = switch (returnsFive()) { | ||
| 130 | 1, 2, 3 => 1, | ||
| 131 | 4, 5, 6 => 2, | ||
| 132 | else => @as(i32, 3), | ||
| 133 | }; | ||
| 134 | try expect(x == 2); | ||
| 135 | } | ||
| 136 | fn returnsFive() i32 { | ||
| 137 | return 5; | ||
| 138 | } | ||
| 139 | |||
| 140 | const Number = union(enum) { | ||
| 141 | One: u64, | ||
| 142 | Two: u8, | ||
| 143 | Three: f32, | ||
| 144 | }; | ||
| 145 | |||
| 146 | const number = Number{ .Three = 1.23 }; | ||
| 147 | |||
| 148 | fn returnsFalse() bool { | ||
| 149 | switch (number) { | ||
| 150 | Number.One => |x| return x > 1234, | ||
| 151 | Number.Two => |x| return x == 'a', | ||
| 152 | Number.Three => |x| return x > 12.34, | ||
| 153 | } | ||
| 154 | } | ||
| 155 | test "switch on const enum with var" { | ||
| 156 | try expect(!returnsFalse()); | ||
| 157 | } | ||
| 158 | |||
| 159 | test "switch on type" { | ||
| 160 | try expect(trueIfBoolFalseOtherwise(bool)); | ||
| 161 | try expect(!trueIfBoolFalseOtherwise(i32)); | ||
| 162 | } | ||
| 163 | |||
| 164 | fn trueIfBoolFalseOtherwise(comptime T: type) bool { | ||
| 165 | return switch (T) { | ||
| 166 | bool => true, | ||
| 167 | else => false, | ||
| 168 | }; | ||
| 169 | } | ||
| 170 | |||
| 171 | test "switch handles all cases of number" { | 48 | test "switch handles all cases of number" { |
| 172 | try testSwitchHandleAllCases(); | 49 | try testSwitchHandleAllCases(); |
| 173 | comptime try testSwitchHandleAllCases(); | 50 | comptime try testSwitchHandleAllCases(); |
| ... | @@ -237,57 +114,6 @@ test "capture value of switch with all unreachable prongs" { | ... | @@ -237,57 +114,6 @@ test "capture value of switch with all unreachable prongs" { |
| 237 | try expect(x == 1); | 114 | try expect(x == 1); |
| 238 | } | 115 | } |
| 239 | 116 | ||
| 240 | test "switching on booleans" { | ||
| 241 | try testSwitchOnBools(); | ||
| 242 | comptime try testSwitchOnBools(); | ||
| 243 | } | ||
| 244 | |||
| 245 | fn testSwitchOnBools() !void { | ||
| 246 | try expect(testSwitchOnBoolsTrueAndFalse(true) == false); | ||
| 247 | try expect(testSwitchOnBoolsTrueAndFalse(false) == true); | ||
| 248 | |||
| 249 | try expect(testSwitchOnBoolsTrueWithElse(true) == false); | ||
| 250 | try expect(testSwitchOnBoolsTrueWithElse(false) == true); | ||
| 251 | |||
| 252 | try expect(testSwitchOnBoolsFalseWithElse(true) == false); | ||
| 253 | try expect(testSwitchOnBoolsFalseWithElse(false) == true); | ||
| 254 | } | ||
| 255 | |||
| 256 | fn testSwitchOnBoolsTrueAndFalse(x: bool) bool { | ||
| 257 | return switch (x) { | ||
| 258 | true => false, | ||
| 259 | false => true, | ||
| 260 | }; | ||
| 261 | } | ||
| 262 | |||
| 263 | fn testSwitchOnBoolsTrueWithElse(x: bool) bool { | ||
| 264 | return switch (x) { | ||
| 265 | true => false, | ||
| 266 | else => true, | ||
| 267 | }; | ||
| 268 | } | ||
| 269 | |||
| 270 | fn testSwitchOnBoolsFalseWithElse(x: bool) bool { | ||
| 271 | return switch (x) { | ||
| 272 | false => true, | ||
| 273 | else => false, | ||
| 274 | }; | ||
| 275 | } | ||
| 276 | |||
| 277 | test "u0" { | ||
| 278 | var val: u0 = 0; | ||
| 279 | switch (val) { | ||
| 280 | 0 => try expect(val == 0), | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | test "undefined.u0" { | ||
| 285 | var val: u0 = undefined; | ||
| 286 | switch (val) { | ||
| 287 | 0 => try expect(val == 0), | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 291 | test "anon enum literal used in switch on union enum" { | 117 | test "anon enum literal used in switch on union enum" { |
| 292 | const Foo = union(enum) { | 118 | const Foo = union(enum) { |
| 293 | a: i32, | 119 | a: i32, |
| ... | @@ -435,54 +261,6 @@ test "switch prongs with cases with identical payload types" { | ... | @@ -435,54 +261,6 @@ test "switch prongs with cases with identical payload types" { |
| 435 | comptime try S.doTheTest(); | 261 | comptime try S.doTheTest(); |
| 436 | } | 262 | } |
| 437 | 263 | ||
| 438 | test "switch with disjoint range" { | ||
| 439 | var q: u8 = 0; | ||
| 440 | switch (q) { | ||
| 441 | 0...125 => {}, | ||
| 442 | 127...255 => {}, | ||
| 443 | 126...126 => {}, | ||
| 444 | } | ||
| 445 | } | ||
| 446 | |||
| 447 | test "switch variable for range and multiple prongs" { | ||
| 448 | const S = struct { | ||
| 449 | fn doTheTest() !void { | ||
| 450 | var u: u8 = 16; | ||
| 451 | try doTheSwitch(u); | ||
| 452 | comptime try doTheSwitch(u); | ||
| 453 | var v: u8 = 42; | ||
| 454 | try doTheSwitch(v); | ||
| 455 | comptime try doTheSwitch(v); | ||
| 456 | } | ||
| 457 | fn doTheSwitch(q: u8) !void { | ||
| 458 | switch (q) { | ||
| 459 | 0...40 => |x| try expect(x == 16), | ||
| 460 | 41, 42, 43 => |x| try expect(x == 42), | ||
| 461 | else => try expect(false), | ||
| 462 | } | ||
| 463 | } | ||
| 464 | }; | ||
| 465 | _ = S; | ||
| 466 | } | ||
| 467 | |||
| 468 | var state: u32 = 0; | ||
| 469 | fn poll() void { | ||
| 470 | switch (state) { | ||
| 471 | 0 => { | ||
| 472 | state = 1; | ||
| 473 | }, | ||
| 474 | else => { | ||
| 475 | state += 1; | ||
| 476 | }, | ||
| 477 | } | ||
| 478 | } | ||
| 479 | |||
| 480 | test "switch on global mutable var isn't constant-folded" { | ||
| 481 | while (state < 2) { | ||
| 482 | poll(); | ||
| 483 | } | ||
| 484 | } | ||
| 485 | |||
| 486 | test "switch on pointer type" { | 264 | test "switch on pointer type" { |
| 487 | const S = struct { | 265 | const S = struct { |
| 488 | const X = struct { | 266 | const X = struct { |
| ... | @@ -527,7 +305,7 @@ test "switch on error set with single else" { | ... | @@ -527,7 +305,7 @@ test "switch on error set with single else" { |
| 527 | comptime try S.doTheTest(); | 305 | comptime try S.doTheTest(); |
| 528 | } | 306 | } |
| 529 | 307 | ||
| 530 | test "while copies its payload" { | 308 | test "switch capture copies its payload" { |
| 531 | const S = struct { | 309 | const S = struct { |
| 532 | fn doTheTest() !void { | 310 | fn doTheTest() !void { |
| 533 | var tmp: union(enum) { | 311 | var tmp: union(enum) { |