authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-25 15:52:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-25 15:52:21-07:00
log97dc5f6eb531c91e8bd23a5589cae64e0a4561e8
tree297dba8e3be1668c81e75f9e7afc30e999c71e9d
parent8509e7111d80a07e778aa2a57d58d2bea6945014

Sema: fix switch that covers full integer range


3 files changed, 57 insertions(+), 46 deletions(-)

src/Sema.zig+20-9
......@@ -396,6 +396,14 @@ pub const Block = struct {
396396 return result_index;
397397 }
398398
399 fn addUnreachable(block: *Block, src: LazySrcLoc, safety_check: bool) !void {
400 if (safety_check and block.wantSafety()) {
401 _ = try block.sema.safetyPanic(block, src, .unreach);
402 } else {
403 _ = try block.addNoOp(.unreach);
404 }
405 }
406
399407 pub fn startAnonDecl(block: *Block) !WipAnonDecl {
400408 return WipAnonDecl{
401409 .block = block,
......@@ -6371,14 +6379,22 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
63716379 }
63726380
63736381 var final_else_body: []const Air.Inst.Index = &.{};
6374 if (special.body.len != 0) {
6382 if (special.body.len != 0 or !is_first) {
63756383 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
63766384 defer wip_captures.deinit();
63776385
63786386 case_block.instructions.shrinkRetainingCapacity(0);
63796387 case_block.wip_capture_scope = wip_captures.scope;
63806388
6381 _ = try sema.analyzeBody(&case_block, special.body);
6389 if (special.body.len != 0) {
6390 _ = try sema.analyzeBody(&case_block, special.body);
6391 } else {
6392 // We still need a terminator in this block, but we have proven
6393 // that it is unreachable.
6394 // TODO this should be a special safety panic other than unreachable, something
6395 // like "panic: switch operand had corrupt value not allowed by the type"
6396 try case_block.addUnreachable(src, true);
6397 }
63826398
63836399 try wip_captures.finalize();
63846400
......@@ -8963,15 +8979,10 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
89638979
89648980 const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable";
89658981 const src = inst_data.src();
8966 const safety_check = inst_data.safety;
89678982 try sema.requireRuntimeBlock(block, src);
89688983 // TODO Add compile error for @optimizeFor occurring too late in a scope.
8969 if (safety_check and block.wantSafety()) {
8970 return sema.safetyPanic(block, src, .unreach);
8971 } else {
8972 _ = try block.addNoOp(.unreach);
8973 return always_noreturn;
8974 }
8984 try block.addUnreachable(src, inst_data.safety);
8985 return always_noreturn;
89758986}
89768987
89778988fn zirRetErrValue(
test/behavior/switch.zig+37
......@@ -262,3 +262,40 @@ fn testSwitchEnumPtrCapture() !void {
262262 else => unreachable,
263263 }
264264}
265
266test "switch handles all cases of number" {
267 try testSwitchHandleAllCases();
268 comptime try testSwitchHandleAllCases();
269}
270
271fn testSwitchHandleAllCases() !void {
272 try expect(testSwitchHandleAllCasesExhaustive(0) == 3);
273 try expect(testSwitchHandleAllCasesExhaustive(1) == 2);
274 try expect(testSwitchHandleAllCasesExhaustive(2) == 1);
275 try expect(testSwitchHandleAllCasesExhaustive(3) == 0);
276
277 try expect(testSwitchHandleAllCasesRange(100) == 0);
278 try expect(testSwitchHandleAllCasesRange(200) == 1);
279 try expect(testSwitchHandleAllCasesRange(201) == 2);
280 try expect(testSwitchHandleAllCasesRange(202) == 4);
281 try expect(testSwitchHandleAllCasesRange(230) == 3);
282}
283
284fn testSwitchHandleAllCasesExhaustive(x: u2) u2 {
285 return switch (x) {
286 0 => @as(u2, 3),
287 1 => 2,
288 2 => 1,
289 3 => 0,
290 };
291}
292
293fn testSwitchHandleAllCasesRange(x: u8) u8 {
294 return switch (x) {
295 0...100 => @as(u8, 0),
296 101...200 => 1,
297 201, 203 => 2,
298 202 => 4,
299 204...255 => 3,
300 };
301}
test/behavior/switch_stage1.zig-37
......@@ -3,43 +3,6 @@ const expect = std.testing.expect;
33const expectError = std.testing.expectError;
44const expectEqual = std.testing.expectEqual;
55
6test "switch handles all cases of number" {
7 try testSwitchHandleAllCases();
8 comptime try testSwitchHandleAllCases();
9}
10
11fn testSwitchHandleAllCases() !void {
12 try expect(testSwitchHandleAllCasesExhaustive(0) == 3);
13 try expect(testSwitchHandleAllCasesExhaustive(1) == 2);
14 try expect(testSwitchHandleAllCasesExhaustive(2) == 1);
15 try expect(testSwitchHandleAllCasesExhaustive(3) == 0);
16
17 try expect(testSwitchHandleAllCasesRange(100) == 0);
18 try expect(testSwitchHandleAllCasesRange(200) == 1);
19 try expect(testSwitchHandleAllCasesRange(201) == 2);
20 try expect(testSwitchHandleAllCasesRange(202) == 4);
21 try expect(testSwitchHandleAllCasesRange(230) == 3);
22}
23
24fn testSwitchHandleAllCasesExhaustive(x: u2) u2 {
25 return switch (x) {
26 0 => @as(u2, 3),
27 1 => 2,
28 2 => 1,
29 3 => 0,
30 };
31}
32
33fn testSwitchHandleAllCasesRange(x: u8) u8 {
34 return switch (x) {
35 0...100 => @as(u8, 0),
36 101...200 => 1,
37 201, 203 => 2,
38 202 => 4,
39 204...255 => 3,
40 };
41}
42
436test "switch all prongs unreachable" {
447 try testAllProngsUnreachable();
458 comptime try testAllProngsUnreachable();