| author | |
| committer | |
| log | 01546e68cd0d82ef78498a10649e6bc2937680da |
| tree | 19eb970a346b362eac55f7e73eb7ee3bfbf90cd7 |
| parent | 3a4a7d2ca378862dd6b31678a143315a9e306f8c |
| signature |
11 files changed, 127 insertions(+), 114 deletions(-)
doc/langref.html.in+1-1| ... | ... | @@ -2595,7 +2595,7 @@ or |
| 2595 | 2595 | |
| 2596 | 2596 | {#header_close#} |
| 2597 | 2597 | |
| 2598 | {#header_open|Switching on errors#} | |
| 2598 | {#header_open|Switching on Errors#} | |
| 2599 | 2599 | <p> |
| 2600 | 2600 | When switching on errors, some special cases are allowed to simplify generic programming patterns: |
| 2601 | 2601 | </p> |
doc/langref/test_switch_on_errors.zig+4-1| ... | ... | @@ -12,7 +12,10 @@ test "unreachable else prong" { |
| 12 | 12 | switch (openFile0()) { |
| 13 | 13 | error.AccessDenied, error.FileNotFound => |e| return e, |
| 14 | 14 | error.OutOfMemory => {}, |
| 15 | else => unreachable, // technically unreachable, but will still compile! | |
| 15 | // 'openFile0' cannot return any more errors, so an 'else' prong would be | |
| 16 | // statically known to be unreachable. Nonetheless, in this case, adding | |
| 17 | // one does not raise an "unreachable else prong" compile error: | |
| 18 | else => unreachable, | |
| 16 | 19 | } |
| 17 | 20 | |
| 18 | 21 | // Allowed unreachable else prongs are: |
doc/langref/test_tagged_union.zig+4-1| ... | ... | @@ -20,7 +20,10 @@ test "switch on tagged union" { |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | 22 | switch (c) { |
| 23 | .ok => |_, tag| try expect(tag == .ok), | |
| 23 | .ok => |_, tag| { | |
| 24 | // Because we're in the '.ok' prong, 'tag' is compile-time known to be '.ok': | |
| 25 | comptime std.debug.assert(tag == .ok); | |
| 26 | }, | |
| 24 | 27 | .not_ok => unreachable, |
| 25 | 28 | } |
| 26 | 29 | } |
src/Air/Liveness.zig+1-4| ... | ... | @@ -176,10 +176,7 @@ pub fn analyze(zcu: *Zcu, air: Air, intern_pool: *InternPool) Allocator.Error!Li |
| 176 | 176 | data.old_extra = a.extra; |
| 177 | 177 | a.extra = .{}; |
| 178 | 178 | try analyzeBody(&a, .main_analysis, &data, main_body); |
| 179 | if (std.debug.runtime_safety and data.live_set.count() != 0) { | |
| 180 | log.debug("instructions still in live set after analysis: {f}", .{fmtInstSet(&data.live_set)}); | |
| 181 | @panic("liveness analysis failed"); | |
| 182 | } | |
| 179 | assert(data.live_set.count() == 0); | |
| 183 | 180 | } |
| 184 | 181 | |
| 185 | 182 | return .{ |
src/Sema.zig+41-27| ... | ... | @@ -12591,6 +12591,7 @@ fn resolveSwitchProng( |
| 12591 | 12591 | sema.typeOf(operand.simple.by_val), |
| 12592 | 12592 | capture_src, |
| 12593 | 12593 | inline_case_capture, |
| 12594 | kind, | |
| 12594 | 12595 | ); |
| 12595 | 12596 | sema.inst_map.putAssumeCapacity(tag_inst, tag_ref); |
| 12596 | 12597 | break :inst tag_inst; |
| ... | ... | @@ -12723,6 +12724,7 @@ fn analyzeSwitchProng( |
| 12723 | 12724 | operand_ty, |
| 12724 | 12725 | capture_src, |
| 12725 | 12726 | inline_case_capture, |
| 12727 | kind, | |
| 12726 | 12728 | ); |
| 12727 | 12729 | sema.inst_map.putAssumeCapacity(tag_inst, tag_ref); |
| 12728 | 12730 | break :inst tag_inst; |
| ... | ... | @@ -12743,6 +12745,7 @@ fn analyzeSwitchTagCapture( |
| 12743 | 12745 | operand_ty: Type, |
| 12744 | 12746 | capture_src: LazySrcLoc, |
| 12745 | 12747 | inline_case_capture: Air.Inst.Ref, |
| 12748 | kind: SwitchProngKind, | |
| 12746 | 12749 | ) CompileError!Air.Inst.Ref { |
| 12747 | 12750 | const pt = sema.pt; |
| 12748 | 12751 | const zcu = pt.zcu; |
| ... | ... | @@ -12760,6 +12763,10 @@ fn analyzeSwitchTagCapture( |
| 12760 | 12763 | if (inline_case_capture != .none) { |
| 12761 | 12764 | return inline_case_capture; // this already is the tag, it's what we're switching on! |
| 12762 | 12765 | } |
| 12766 | switch (kind) { | |
| 12767 | .has_ranges, .special => {}, | |
| 12768 | .item_refs => |refs| if (refs.len == 1) return refs[0], | |
| 12769 | } | |
| 12763 | 12770 | const tag_ty = operand_ty.unionTagType(zcu).?; |
| 12764 | 12771 | return sema.unionToTag(case_block, tag_ty, operand_val, tag_capture_src); |
| 12765 | 12772 | } |
| ... | ... | @@ -13150,10 +13157,12 @@ fn analyzeSwitchPayloadCapture( |
| 13150 | 13157 | return sema.bitCast(case_block, error_ty, operand_val, operand_src, null); |
| 13151 | 13158 | }, |
| 13152 | 13159 | else => { |
| 13153 | // In this case the capture value is just the passed-through value | |
| 13154 | // of the switch condition. | |
| 13160 | // In this case the capture value is just the passed-through value of the | |
| 13161 | // switch condition. It is comptime-known if there is only one item. | |
| 13155 | 13162 | if (capture_by_ref) { |
| 13156 | 13163 | return operand_ptr; |
| 13164 | } else if (case_vals.len == 1) { | |
| 13165 | return case_vals[0]; | |
| 13157 | 13166 | } else { |
| 13158 | 13167 | return operand_val; |
| 13159 | 13168 | } |
| ... | ... | @@ -31361,17 +31370,19 @@ fn resolvePtrIsNonErrVal( |
| 31361 | 31370 | assert(ptr_ty.zigTypeTag(zcu) == .pointer); |
| 31362 | 31371 | const child_ty = ptr_ty.childType(zcu); |
| 31363 | 31372 | |
| 31364 | const child_tag = child_ty.zigTypeTag(zcu); | |
| 31365 | if (child_tag != .error_set and child_tag != .error_union) return .true; | |
| 31366 | if (child_tag == .error_set) return .false; | |
| 31367 | assert(child_tag == .error_union); | |
| 31373 | if (try sema.resolveIsNonErrFromType(block, src, child_ty)) |res| { | |
| 31374 | return res; | |
| 31375 | } | |
| 31376 | assert(child_ty.zigTypeTag(zcu) == .error_union); | |
| 31368 | 31377 | |
| 31369 | if (try sema.resolveValue(operand)) |ptr_val| { | |
| 31370 | if (ptr_val.isUndef(zcu)) return .undef_bool; | |
| 31371 | if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |val| { | |
| 31372 | return try sema.resolveIsNonErrVal(block, src, .fromValue(val)); | |
| 31378 | if (try sema.resolveValue(operand)) |eu_ptr_val| { | |
| 31379 | if (eu_ptr_val.isUndef(zcu)) return .undef_bool; | |
| 31380 | if (try sema.pointerDeref(block, src, eu_ptr_val, ptr_ty)) |err_union| { | |
| 31381 | if (err_union.isUndef(zcu)) return .undef_bool; | |
| 31382 | return .makeBool(err_union.getErrorName(zcu) == .none); | |
| 31373 | 31383 | } |
| 31374 | 31384 | } |
| 31385 | ||
| 31375 | 31386 | return null; |
| 31376 | 31387 | } |
| 31377 | 31388 | |
| ... | ... | @@ -31380,11 +31391,30 @@ fn resolveIsNonErrVal( |
| 31380 | 31391 | block: *Block, |
| 31381 | 31392 | src: LazySrcLoc, |
| 31382 | 31393 | operand: Air.Inst.Ref, |
| 31394 | ) CompileError!?Value { | |
| 31395 | const zcu = sema.pt.zcu; | |
| 31396 | if (try sema.resolveIsNonErrFromType(block, src, sema.typeOf(operand))) |res| { | |
| 31397 | return res; | |
| 31398 | } | |
| 31399 | assert(sema.typeOf(operand).zigTypeTag(zcu) == .error_union); | |
| 31400 | ||
| 31401 | if (try sema.resolveValue(operand)) |err_union| { | |
| 31402 | if (err_union.isUndef(zcu)) return .undef_bool; | |
| 31403 | return .makeBool(err_union.getErrorName(zcu) == .none); | |
| 31404 | } | |
| 31405 | ||
| 31406 | return null; | |
| 31407 | } | |
| 31408 | ||
| 31409 | fn resolveIsNonErrFromType( | |
| 31410 | sema: *Sema, | |
| 31411 | block: *Block, | |
| 31412 | src: LazySrcLoc, | |
| 31413 | operand_ty: Type, | |
| 31383 | 31414 | ) CompileError!?Value { |
| 31384 | 31415 | const pt = sema.pt; |
| 31385 | 31416 | const zcu = pt.zcu; |
| 31386 | 31417 | const ip = &zcu.intern_pool; |
| 31387 | const operand_ty = sema.typeOf(operand); | |
| 31388 | 31418 | const ot = operand_ty.zigTypeTag(zcu); |
| 31389 | 31419 | if (ot != .error_set and ot != .error_union) return .true; |
| 31390 | 31420 | if (ot == .error_set) return .false; |
| ... | ... | @@ -31395,15 +31425,6 @@ fn resolveIsNonErrVal( |
| 31395 | 31425 | return .false; |
| 31396 | 31426 | } |
| 31397 | 31427 | |
| 31398 | if (operand == .undef) { | |
| 31399 | return .undef_bool; | |
| 31400 | } else if (@intFromEnum(operand) < InternPool.static_len) { | |
| 31401 | // None of the ref tags can be errors. | |
| 31402 | return .true; | |
| 31403 | } | |
| 31404 | ||
| 31405 | const maybe_operand_val = try sema.resolveValue(operand); | |
| 31406 | ||
| 31407 | 31428 | // exception if the error union error set is known to be empty, |
| 31408 | 31429 | // we allow the comparison but always make it comptime-known. |
| 31409 | 31430 | const set_ty = ip.errorUnionSet(operand_ty.toIntern()); |
| ... | ... | @@ -31419,9 +31440,6 @@ fn resolveIsNonErrVal( |
| 31419 | 31440 | else => |i| if (ip.indexToKey(i).error_set_type.names.len != 0) break :blk, |
| 31420 | 31441 | } |
| 31421 | 31442 | |
| 31422 | if (maybe_operand_val != null) break :blk; | |
| 31423 | ||
| 31424 | // Try to avoid resolving inferred error set if possible. | |
| 31425 | 31443 | if (ies.errors.count() != 0) return null; |
| 31426 | 31444 | switch (ies.resolved) { |
| 31427 | 31445 | .anyerror_type => return null, |
| ... | ... | @@ -31450,7 +31468,6 @@ fn resolveIsNonErrVal( |
| 31450 | 31468 | .none => {}, |
| 31451 | 31469 | else => |i| if (ip.indexToKey(i).error_set_type.names.len != 0) break :blk, |
| 31452 | 31470 | } |
| 31453 | if (maybe_operand_val != null) break :blk; | |
| 31454 | 31471 | if (sema.fn_ret_ty_ies) |ies| { |
| 31455 | 31472 | if (ies.func == func_index) { |
| 31456 | 31473 | // Try to avoid resolving inferred error set if possible. |
| ... | ... | @@ -31479,9 +31496,6 @@ fn resolveIsNonErrVal( |
| 31479 | 31496 | }, |
| 31480 | 31497 | } |
| 31481 | 31498 | |
| 31482 | if (maybe_operand_val) |err_union| { | |
| 31483 | return if (err_union.isUndef(zcu)) .undef_bool else if (err_union.getErrorName(zcu) == .none) .true else .false; | |
| 31484 | } | |
| 31485 | 31499 | return null; |
| 31486 | 31500 | } |
| 31487 | 31501 |
src/Zcu.zig+1-10| ... | ... | @@ -2221,16 +2221,7 @@ pub const SrcLoc = struct { |
| 2221 | 2221 | continue; |
| 2222 | 2222 | } |
| 2223 | 2223 | return tree.nodeToSpan(item_node); |
| 2224 | } else { | |
| 2225 | for (case.ast.values) |item_node| { | |
| 2226 | const item_span = tree.nodeToSpan(item_node); | |
| 2227 | std.debug.print("{s}\n", .{tree.source[item_span.start..item_span.end]}); | |
| 2228 | } | |
| 2229 | std.debug.print("want_case_idx={any}\n", .{want_case_idx}); | |
| 2230 | std.debug.print("want_item_idx={any}\n", .{want_item_idx}); | |
| 2231 | unreachable; | |
| 2232 | } | |
| 2233 | // } else unreachable; | |
| 2224 | } else unreachable; | |
| 2234 | 2225 | }, |
| 2235 | 2226 | .range => { |
| 2236 | 2227 | var range_i: u32 = 0; |
test/behavior/for.zig+1-1| ... | ... | @@ -525,7 +525,7 @@ test "for loop 0 length range" { |
| 525 | 525 | } |
| 526 | 526 | } |
| 527 | 527 | |
| 528 | test "labeled break from else prong" { | |
| 528 | test "labeled break from else" { | |
| 529 | 529 | const S = struct { |
| 530 | 530 | fn doTheTest(x: u32) !void { |
| 531 | 531 | var y: u32 = 0; |
test/behavior/switch.zig+55-56| ... | ... | @@ -1128,20 +1128,17 @@ test "decl literals as switch cases" { |
| 1128 | 1128 | |
| 1129 | 1129 | const foo: @This() = @enumFromInt(0xa); |
| 1130 | 1130 | |
| 1131 | fn doTheTest() !void { | |
| 1132 | var e: @This() = .foo; | |
| 1133 | _ = &e; | |
| 1134 | const ok = switch (e) { | |
| 1135 | .bar => false, | |
| 1136 | .foo => true, | |
| 1137 | else => false, | |
| 1138 | }; | |
| 1139 | try expect(ok); | |
| 1131 | fn doTheTest(e: @This()) !void { | |
| 1132 | switch (e) { | |
| 1133 | .bar => return error.TestFailed, | |
| 1134 | .foo => {}, | |
| 1135 | else => return error.TestFailed, | |
| 1136 | } | |
| 1140 | 1137 | } |
| 1141 | 1138 | }; |
| 1142 | 1139 | |
| 1143 | try E.doTheTest(); | |
| 1144 | try comptime E.doTheTest(); | |
| 1140 | try E.doTheTest(.foo); | |
| 1141 | try comptime E.doTheTest(.foo); | |
| 1145 | 1142 | } |
| 1146 | 1143 | |
| 1147 | 1144 | // TODO audit after #15909 and/or #19855 are decided/implemented |
| ... | ... | @@ -1152,32 +1149,30 @@ test "switch with uninstantiable union fields" { |
| 1152 | 1149 | b: noreturn, |
| 1153 | 1150 | c: error{}, |
| 1154 | 1151 | |
| 1155 | fn doTheTest() !void { | |
| 1156 | var u: @This() = .ok; | |
| 1157 | _ = &u; | |
| 1158 | try expect(switch (u) { | |
| 1159 | .ok => true, | |
| 1152 | fn doTheTest(u: @This()) void { | |
| 1153 | switch (u) { | |
| 1154 | .ok => {}, | |
| 1160 | 1155 | .a => comptime unreachable, |
| 1161 | 1156 | .b => comptime unreachable, |
| 1162 | 1157 | .c => comptime unreachable, |
| 1163 | }); | |
| 1164 | try expect(switch (u) { | |
| 1165 | .ok => true, | |
| 1158 | } | |
| 1159 | switch (u) { | |
| 1160 | .ok => {}, | |
| 1166 | 1161 | .a, .b, .c => comptime unreachable, |
| 1167 | }); | |
| 1168 | try expect(switch (u) { | |
| 1169 | .ok => true, | |
| 1162 | } | |
| 1163 | switch (u) { | |
| 1164 | .ok => {}, | |
| 1170 | 1165 | else => comptime unreachable, |
| 1171 | }); | |
| 1172 | try expect(switch (u) { | |
| 1166 | } | |
| 1167 | switch (u) { | |
| 1173 | 1168 | .a => comptime unreachable, |
| 1174 | .ok, .b, .c => true, | |
| 1175 | }); | |
| 1169 | .ok, .b, .c => {}, | |
| 1170 | } | |
| 1176 | 1171 | } |
| 1177 | 1172 | }; |
| 1178 | 1173 | |
| 1179 | try U.doTheTest(); | |
| 1180 | try comptime U.doTheTest(); | |
| 1174 | U.doTheTest(.ok); | |
| 1175 | comptime U.doTheTest(.ok); | |
| 1181 | 1176 | } |
| 1182 | 1177 | |
| 1183 | 1178 | test "switch with tag capture" { |
| ... | ... | @@ -1196,8 +1191,8 @@ test "switch with tag capture" { |
| 1196 | 1191 | fn doTheSwitch(u: @This()) !void { |
| 1197 | 1192 | switch (u) { |
| 1198 | 1193 | .a => |nothing, tag| { |
| 1199 | try expect(nothing == {}); | |
| 1200 | try expect(tag == .a); | |
| 1194 | comptime assert(nothing == {}); | |
| 1195 | comptime assert(tag == .a); | |
| 1201 | 1196 | try expect(@intFromEnum(tag) == @intFromEnum(@This().a)); |
| 1202 | 1197 | }, |
| 1203 | 1198 | .b, .d => |_, tag| { |
| ... | ... | @@ -1216,13 +1211,13 @@ test "switch with tag capture" { |
| 1216 | 1211 | } |
| 1217 | 1212 | switch (u) { |
| 1218 | 1213 | inline .a, .b, .c => |payload, tag| { |
| 1219 | if (@TypeOf(payload) == void) try expect(tag == .a); | |
| 1220 | if (@TypeOf(payload) == i32) try expect(tag == .b); | |
| 1221 | if (@TypeOf(payload) == u8) try expect(tag == .c); | |
| 1214 | if (@TypeOf(payload) == void) comptime assert(tag == .a); | |
| 1215 | if (@TypeOf(payload) == i32) comptime assert(tag == .b); | |
| 1216 | if (@TypeOf(payload) == u8) comptime assert(tag == .c); | |
| 1222 | 1217 | }, |
| 1223 | 1218 | inline else => |payload, tag| { |
| 1224 | if (@TypeOf(payload) == i32) try expect(tag == .d); | |
| 1225 | try expect(tag != .e); | |
| 1219 | if (@TypeOf(payload) == i32) comptime assert(tag == .d); | |
| 1220 | comptime assert(tag != .e); | |
| 1226 | 1221 | }, |
| 1227 | 1222 | } |
| 1228 | 1223 | } |
| ... | ... | @@ -1232,7 +1227,7 @@ test "switch with tag capture" { |
| 1232 | 1227 | try comptime U.doTheTest(); |
| 1233 | 1228 | } |
| 1234 | 1229 | |
| 1235 | test "switch with advanced prong items" { | |
| 1230 | test "switch with complex item expressions" { | |
| 1236 | 1231 | const S = struct { |
| 1237 | 1232 | fn doTheTest() !void { |
| 1238 | 1233 | try doTheSwitch(2000, 20); |
| ... | ... | @@ -1278,19 +1273,11 @@ test "switch with advanced prong items" { |
| 1278 | 1273 | } |
| 1279 | 1274 | |
| 1280 | 1275 | test "switch evaluation order" { |
| 1281 | const eval = comptime eval: { | |
| 1282 | var eval = false; | |
| 1283 | const eu: anyerror!u32 = 0; | |
| 1284 | _ = eu catch |err| switch (err) { | |
| 1285 | blk: { | |
| 1286 | eval = true; | |
| 1287 | break :blk error.MyError; | |
| 1288 | } => {}, | |
| 1289 | else => unreachable, | |
| 1290 | }; | |
| 1291 | break :eval eval; | |
| 1276 | const eu: anyerror!u32 = 0; | |
| 1277 | _ = eu catch |err| switch (err) { | |
| 1278 | if (true) @compileError("unreachable") => unreachable, | |
| 1279 | else => unreachable, | |
| 1292 | 1280 | }; |
| 1293 | try comptime expect(!eval); | |
| 1294 | 1281 | } |
| 1295 | 1282 | |
| 1296 | 1283 | test "switch resolves lazy values correctly" { |
| ... | ... | @@ -1298,13 +1285,25 @@ test "switch resolves lazy values correctly" { |
| 1298 | 1285 | a: u16, |
| 1299 | 1286 | b: i16, |
| 1300 | 1287 | }; |
| 1301 | const ok1 = switch (@sizeOf(S)) { | |
| 1302 | 4 => true, | |
| 1303 | else => false, | |
| 1304 | }; | |
| 1305 | const ok2 = switch (@sizeOf(S)) { | |
| 1306 | 4 => true, | |
| 1307 | else => false, | |
| 1288 | switch (@sizeOf(S)) { | |
| 1289 | 4 => {}, | |
| 1290 | else => comptime unreachable, | |
| 1291 | } | |
| 1292 | } | |
| 1293 | ||
| 1294 | test "single-item prong in switch on enum has comptime-known capture" { | |
| 1295 | const E = enum { | |
| 1296 | a, | |
| 1297 | b, | |
| 1298 | c, | |
| 1299 | fn doTheTest(e: @This()) !void { | |
| 1300 | switch (e) { | |
| 1301 | .a => |tag| comptime assert(tag == .a), | |
| 1302 | .b => return error.TestFailed, | |
| 1303 | .c => return error.TestFailed, | |
| 1304 | } | |
| 1305 | } | |
| 1308 | 1306 | }; |
| 1309 | try comptime expect(ok1 == ok2); | |
| 1307 | try E.doTheTest(.a); | |
| 1308 | try comptime E.doTheTest(.a); | |
| 1310 | 1309 | } |
test/behavior/switch_loop.zig+9-8| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | const builtin = @import("builtin"); |
| 2 | 2 | const std = @import("std"); |
| 3 | const assert = std.debug.assert; | |
| 3 | 4 | const expect = std.testing.expect; |
| 4 | 5 | |
| 5 | 6 | test "simple switch loop" { |
| ... | ... | @@ -340,7 +341,7 @@ test "switch loop with single catch-all prong" { |
| 340 | 341 | continue :label .{ .b = 456 }; |
| 341 | 342 | }, |
| 342 | 343 | }; |
| 343 | try expect(ok); | |
| 344 | comptime assert(ok); | |
| 344 | 345 | } |
| 345 | 346 | }; |
| 346 | 347 | try S.doTheTest(); |
| ... | ... | @@ -411,8 +412,8 @@ test "switch loop with tag capture" { |
| 411 | 412 | fn doTheSwitch(u: @This()) !void { |
| 412 | 413 | const ok1 = label: switch (u) { |
| 413 | 414 | .a => |nothing, tag| { |
| 414 | try expect(nothing == {}); | |
| 415 | try expect(tag == .a); | |
| 415 | comptime assert(nothing == {}); | |
| 416 | comptime assert(tag == .a); | |
| 416 | 417 | try expect(@intFromEnum(tag) == @intFromEnum(@This().a)); |
| 417 | 418 | continue :label .{ .d = 456 }; |
| 418 | 419 | }, |
| ... | ... | @@ -438,21 +439,21 @@ test "switch loop with tag capture" { |
| 438 | 439 | const ok2 = label: switch (u) { |
| 439 | 440 | inline .a, .b, .c => |payload, tag| { |
| 440 | 441 | if (@TypeOf(payload) == void) { |
| 441 | try expect(tag == .a); | |
| 442 | comptime assert(tag == .a); | |
| 442 | 443 | continue :label .{ .b = 456 }; |
| 443 | 444 | } |
| 444 | 445 | if (@TypeOf(payload) == i32) { |
| 445 | try expect(tag == .b); | |
| 446 | comptime assert(tag == .b); | |
| 446 | 447 | continue :label .{ .d = payload }; |
| 447 | 448 | } |
| 448 | 449 | if (@TypeOf(payload) == u8) { |
| 449 | try expect(tag == .c); | |
| 450 | comptime assert(tag == .c); | |
| 450 | 451 | continue :label .{ .d = payload }; |
| 451 | 452 | } |
| 452 | 453 | }, |
| 453 | 454 | inline else => |payload, tag| { |
| 454 | if (@TypeOf(payload) == i32) try expect(tag == .d); | |
| 455 | try expect(tag != .e); | |
| 455 | if (@TypeOf(payload) == i32) comptime assert(tag == .d); | |
| 456 | comptime assert(tag != .e); | |
| 456 | 457 | if (payload == 0) break :label false; |
| 457 | 458 | break :label true; |
| 458 | 459 | }, |
test/behavior/switch_on_captured_error.zig+6-1| ... | ... | @@ -17,7 +17,9 @@ test "switch on error union catch capture" { |
| 17 | 17 | try testElse(); |
| 18 | 18 | try testCapture(); |
| 19 | 19 | try testInline(); |
| 20 | try testEmptyErrSet(); | |
| 20 | 21 | try testUnreachableElseProng(); |
| 22 | try testErrNotInSet(); | |
| 21 | 23 | try testAddressOf(); |
| 22 | 24 | } |
| 23 | 25 | |
| ... | ... | @@ -384,8 +386,11 @@ test "switch on error union if else capture" { |
| 384 | 386 | try testCapturePtr(); |
| 385 | 387 | try testInline(); |
| 386 | 388 | try testInlinePtr(); |
| 389 | try testEmptyErrSet(); | |
| 390 | try testEmptyErrSetPtr(); | |
| 387 | 391 | try testUnreachableElseProng(); |
| 388 | 392 | try testUnreachableElseProngPtr(); |
| 393 | try testErrNotInSet(); | |
| 389 | 394 | try testAddressOf(); |
| 390 | 395 | } |
| 391 | 396 | |
| ... | ... | @@ -835,7 +840,7 @@ test "switch on error union if else capture" { |
| 835 | 840 | var a: error{}!u64 = 0; |
| 836 | 841 | _ = &a; |
| 837 | 842 | const b = if (a) |*x| x.* else |err| switch (err) { |
| 838 | error.undefined => @compileError("unreachable"), | |
| 843 | undefined => @compileError("unreachable"), | |
| 839 | 844 | }; |
| 840 | 845 | try expectEqual(@as(u64, 0), b); |
| 841 | 846 | } |
test/behavior/while.zig+4-4| ... | ... | @@ -400,12 +400,12 @@ test "breaking from a loop in an if statement" { |
| 400 | 400 | _ = opt; |
| 401 | 401 | } |
| 402 | 402 | |
| 403 | test "labeled break from else prong" { | |
| 403 | test "labeled break from else" { | |
| 404 | 404 | const S = struct { |
| 405 | 405 | fn doTheTest(x: u32) !void { |
| 406 | var y: u32 = 0; | |
| 407 | const ok = label: while (y < x) : (y += 1) { | |
| 408 | if (y == 10) break :label false; | |
| 406 | const arr: []const u32 = &.{ 1, 3, 10 }; | |
| 407 | const ok = label: for (arr) |y| { | |
| 408 | if (y == x) break :label false; | |
| 409 | 409 | } else { |
| 410 | 410 | break :label true; |
| 411 | 411 | }; |