diff options
| -rw-r--r-- | src/Sema.zig | 29 | ||||
| -rw-r--r-- | test/behavior/switch.zig | 37 | ||||
| -rw-r--r-- | test/behavior/switch_stage1.zig | 37 |
3 files changed, 57 insertions, 46 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index 0e322f2dcc..e7cb40420e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -396,6 +396,14 @@ pub const Block = struct { return result_index; } + fn addUnreachable(block: *Block, src: LazySrcLoc, safety_check: bool) !void { + if (safety_check and block.wantSafety()) { + _ = try block.sema.safetyPanic(block, src, .unreach); + } else { + _ = try block.addNoOp(.unreach); + } + } + pub fn startAnonDecl(block: *Block) !WipAnonDecl { return WipAnonDecl{ .block = block, @@ -6371,14 +6379,22 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } var final_else_body: []const Air.Inst.Index = &.{}; - if (special.body.len != 0) { + if (special.body.len != 0 or !is_first) { var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope); defer wip_captures.deinit(); case_block.instructions.shrinkRetainingCapacity(0); case_block.wip_capture_scope = wip_captures.scope; - _ = try sema.analyzeBody(&case_block, special.body); + if (special.body.len != 0) { + _ = try sema.analyzeBody(&case_block, special.body); + } else { + // We still need a terminator in this block, but we have proven + // that it is unreachable. + // TODO this should be a special safety panic other than unreachable, something + // like "panic: switch operand had corrupt value not allowed by the type" + try case_block.addUnreachable(src, true); + } try wip_captures.finalize(); @@ -8963,15 +8979,10 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable"; const src = inst_data.src(); - const safety_check = inst_data.safety; try sema.requireRuntimeBlock(block, src); // TODO Add compile error for @optimizeFor occurring too late in a scope. - if (safety_check and block.wantSafety()) { - return sema.safetyPanic(block, src, .unreach); - } else { - _ = try block.addNoOp(.unreach); - return always_noreturn; - } + try block.addUnreachable(src, inst_data.safety); + return always_noreturn; } fn zirRetErrValue( diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index d5e4a40500..6df3656760 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -262,3 +262,40 @@ fn testSwitchEnumPtrCapture() !void { else => unreachable, } } + +test "switch handles all cases of number" { + try testSwitchHandleAllCases(); + comptime try testSwitchHandleAllCases(); +} + +fn testSwitchHandleAllCases() !void { + try expect(testSwitchHandleAllCasesExhaustive(0) == 3); + try expect(testSwitchHandleAllCasesExhaustive(1) == 2); + try expect(testSwitchHandleAllCasesExhaustive(2) == 1); + try expect(testSwitchHandleAllCasesExhaustive(3) == 0); + + try expect(testSwitchHandleAllCasesRange(100) == 0); + try expect(testSwitchHandleAllCasesRange(200) == 1); + try expect(testSwitchHandleAllCasesRange(201) == 2); + try expect(testSwitchHandleAllCasesRange(202) == 4); + try expect(testSwitchHandleAllCasesRange(230) == 3); +} + +fn testSwitchHandleAllCasesExhaustive(x: u2) u2 { + return switch (x) { + 0 => @as(u2, 3), + 1 => 2, + 2 => 1, + 3 => 0, + }; +} + +fn testSwitchHandleAllCasesRange(x: u8) u8 { + return switch (x) { + 0...100 => @as(u8, 0), + 101...200 => 1, + 201, 203 => 2, + 202 => 4, + 204...255 => 3, + }; +} diff --git a/test/behavior/switch_stage1.zig b/test/behavior/switch_stage1.zig index c42a9b7894..1b85d767d5 100644 --- a/test/behavior/switch_stage1.zig +++ b/test/behavior/switch_stage1.zig @@ -3,43 +3,6 @@ const expect = std.testing.expect; const expectError = std.testing.expectError; const expectEqual = std.testing.expectEqual; -test "switch handles all cases of number" { - try testSwitchHandleAllCases(); - comptime try testSwitchHandleAllCases(); -} - -fn testSwitchHandleAllCases() !void { - try expect(testSwitchHandleAllCasesExhaustive(0) == 3); - try expect(testSwitchHandleAllCasesExhaustive(1) == 2); - try expect(testSwitchHandleAllCasesExhaustive(2) == 1); - try expect(testSwitchHandleAllCasesExhaustive(3) == 0); - - try expect(testSwitchHandleAllCasesRange(100) == 0); - try expect(testSwitchHandleAllCasesRange(200) == 1); - try expect(testSwitchHandleAllCasesRange(201) == 2); - try expect(testSwitchHandleAllCasesRange(202) == 4); - try expect(testSwitchHandleAllCasesRange(230) == 3); -} - -fn testSwitchHandleAllCasesExhaustive(x: u2) u2 { - return switch (x) { - 0 => @as(u2, 3), - 1 => 2, - 2 => 1, - 3 => 0, - }; -} - -fn testSwitchHandleAllCasesRange(x: u8) u8 { - return switch (x) { - 0...100 => @as(u8, 0), - 101...200 => 1, - 201, 203 => 2, - 202 => 4, - 204...255 => 3, - }; -} - test "switch all prongs unreachable" { try testAllProngsUnreachable(); comptime try testAllProngsUnreachable(); |
