| author | |
| committer | |
| log | 97dc5f6eb531c91e8bd23a5589cae64e0a4561e8 |
| tree | 297dba8e3be1668c81e75f9e7afc30e999c71e9d |
| parent | 8509e7111d80a07e778aa2a57d58d2bea6945014 |
3 files changed, 57 insertions(+), 46 deletions(-)
src/Sema.zig+20-9| ... | ... | @@ -396,6 +396,14 @@ pub const Block = struct { |
| 396 | 396 | return result_index; |
| 397 | 397 | } |
| 398 | 398 | |
| 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 | ||
| 399 | 407 | pub fn startAnonDecl(block: *Block) !WipAnonDecl { |
| 400 | 408 | return WipAnonDecl{ |
| 401 | 409 | .block = block, |
| ... | ... | @@ -6371,14 +6379,22 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 6371 | 6379 | } |
| 6372 | 6380 | |
| 6373 | 6381 | var final_else_body: []const Air.Inst.Index = &.{}; |
| 6374 | if (special.body.len != 0) { | |
| 6382 | if (special.body.len != 0 or !is_first) { | |
| 6375 | 6383 | var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope); |
| 6376 | 6384 | defer wip_captures.deinit(); |
| 6377 | 6385 | |
| 6378 | 6386 | case_block.instructions.shrinkRetainingCapacity(0); |
| 6379 | 6387 | case_block.wip_capture_scope = wip_captures.scope; |
| 6380 | 6388 | |
| 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 | } | |
| 6382 | 6398 | |
| 6383 | 6399 | try wip_captures.finalize(); |
| 6384 | 6400 | |
| ... | ... | @@ -8963,15 +8979,10 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 8963 | 8979 | |
| 8964 | 8980 | const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable"; |
| 8965 | 8981 | const src = inst_data.src(); |
| 8966 | const safety_check = inst_data.safety; | |
| 8967 | 8982 | try sema.requireRuntimeBlock(block, src); |
| 8968 | 8983 | // 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; | |
| 8975 | 8986 | } |
| 8976 | 8987 | |
| 8977 | 8988 | fn zirRetErrValue( |
test/behavior/switch.zig+37| ... | ... | @@ -262,3 +262,40 @@ fn testSwitchEnumPtrCapture() !void { |
| 262 | 262 | else => unreachable, |
| 263 | 263 | } |
| 264 | 264 | } |
| 265 | ||
| 266 | test "switch handles all cases of number" { | |
| 267 | try testSwitchHandleAllCases(); | |
| 268 | comptime try testSwitchHandleAllCases(); | |
| 269 | } | |
| 270 | ||
| 271 | fn 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 | ||
| 284 | fn 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 | ||
| 293 | fn 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; |
| 3 | 3 | const expectError = std.testing.expectError; |
| 4 | 4 | const expectEqual = std.testing.expectEqual; |
| 5 | 5 | |
| 6 | test "switch handles all cases of number" { | |
| 7 | try testSwitchHandleAllCases(); | |
| 8 | comptime try testSwitchHandleAllCases(); | |
| 9 | } | |
| 10 | ||
| 11 | fn 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 | ||
| 24 | fn 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 | ||
| 33 | fn 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 | ||
| 43 | 6 | test "switch all prongs unreachable" { |
| 44 | 7 | try testAllProngsUnreachable(); |
| 45 | 8 | comptime try testAllProngsUnreachable(); |