authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-01-11 14:27:00+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-01-11 14:37:28+00:00
log01546e68cd0d82ef78498a10649e6bc2937680da
tree19eb970a346b362eac55f7e73eb7ee3bfbf90cd7
parent3a4a7d2ca378862dd6b31678a143315a9e306f8c
signaturelock-open Commit is signed but in an unrecognized format.

compiler: handle switch rewrite review feedback


11 files changed, 127 insertions(+), 114 deletions(-)

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