mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 21:38:33 +00:00
Sema: fix switch that covers full integer range
This commit is contained in:
parent
8509e7111d
commit
97dc5f6eb5
29
src/Sema.zig
29
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(
|
||||
|
||||
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user