@@ -4826,26 +4826,8 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
4826
4826
return Air.Inst.Ref.anyerror_type;
4827
4827
}
4828
4828
// Resolve both error sets now.
4829
- const lhs_names = switch (lhs_ty.tag()) {
4830
- .error_set_single => blk: {
4831
- // Work around coercion problems
4832
- const tmp: *const [1][]const u8 = &lhs_ty.castTag(.error_set_single).?.data;
4833
- break :blk tmp;
4834
- },
4835
- .error_set_merged => lhs_ty.castTag(.error_set_merged).?.data.keys(),
4836
- .error_set => lhs_ty.castTag(.error_set).?.data.names.keys(),
4837
- else => unreachable,
4838
- };
4839
-
4840
- const rhs_names = switch (rhs_ty.tag()) {
4841
- .error_set_single => blk: {
4842
- const tmp: *const [1][]const u8 = &rhs_ty.castTag(.error_set_single).?.data;
4843
- break :blk tmp;
4844
- },
4845
- .error_set_merged => rhs_ty.castTag(.error_set_merged).?.data.keys(),
4846
- .error_set => rhs_ty.castTag(.error_set).?.data.names.keys(),
4847
- else => unreachable,
4848
- };
4829
+ const lhs_names = lhs_ty.errorSetNames();
4830
+ const rhs_names = rhs_ty.errorSetNames();
4849
4831
4850
4832
// TODO do we really want to create a Decl for this?
4851
4833
// The reason we do it right now is for memory management.
@@ -6080,6 +6062,8 @@ fn zirSwitchCond(
6080
6062
}
6081
6063
}
6082
6064
6065
+ const SwitchErrorSet = std.StringHashMap(Module.SwitchProngSrc);
6066
+
6083
6067
fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
6084
6068
const tracy = trace(@src());
6085
6069
defer tracy.end();
@@ -6250,8 +6234,110 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
6250
6234
},
6251
6235
}
6252
6236
},
6237
+ .ErrorSet => {
6238
+ var seen_errors = SwitchErrorSet.init(gpa);
6239
+ defer seen_errors.deinit();
6240
+
6241
+ var extra_index: usize = special.end;
6242
+ {
6243
+ var scalar_i: u32 = 0;
6244
+ while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
6245
+ const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
6246
+ extra_index += 1;
6247
+ const body_len = sema.code.extra[extra_index];
6248
+ extra_index += 1;
6249
+ extra_index += body_len;
6250
+
6251
+ try sema.validateSwitchItemError(
6252
+ block,
6253
+ &seen_errors,
6254
+ item_ref,
6255
+ src_node_offset,
6256
+ .{ .scalar = scalar_i },
6257
+ );
6258
+ }
6259
+ }
6260
+ {
6261
+ var multi_i: u32 = 0;
6262
+ while (multi_i < multi_cases_len) : (multi_i += 1) {
6263
+ const items_len = sema.code.extra[extra_index];
6264
+ extra_index += 1;
6265
+ const ranges_len = sema.code.extra[extra_index];
6266
+ extra_index += 1;
6267
+ const body_len = sema.code.extra[extra_index];
6268
+ extra_index += 1;
6269
+ const items = sema.code.refSlice(extra_index, items_len);
6270
+ extra_index += items_len + body_len;
6271
+
6272
+ for (items) |item_ref, item_i| {
6273
+ try sema.validateSwitchItemError(
6274
+ block,
6275
+ &seen_errors,
6276
+ item_ref,
6277
+ src_node_offset,
6278
+ .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
6279
+ );
6280
+ }
6281
+
6282
+ try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
6283
+ }
6284
+ }
6285
+
6286
+ if (operand_ty.isAnyError()) {
6287
+ if (special_prong != .@"else") {
6288
+ return sema.fail(
6289
+ block,
6290
+ src,
6291
+ "switch must handle all possibilities",
6292
+ .{},
6293
+ );
6294
+ }
6295
+ } else {
6296
+ var maybe_msg: ?*Module.ErrorMsg = null;
6297
+ errdefer if (maybe_msg) |msg| msg.destroy(sema.gpa);
6298
+
6299
+ for (operand_ty.errorSetNames()) |error_name| {
6300
+ if (!seen_errors.contains(error_name) and special_prong != .@"else") {
6301
+ const msg = maybe_msg orelse blk: {
6302
+ maybe_msg = try sema.errMsg(
6303
+ block,
6304
+ src,
6305
+ "switch must handle all possibilities",
6306
+ .{},
6307
+ );
6308
+ break :blk maybe_msg.?;
6309
+ };
6310
+
6311
+ try sema.errNote(
6312
+ block,
6313
+ src,
6314
+ msg,
6315
+ "unhandled error value: error.{s}",
6316
+ .{error_name},
6317
+ );
6318
+ }
6319
+ }
6253
6320
6254
- .ErrorSet => return sema.fail(block, src, "TODO validate switch .ErrorSet", .{}),
6321
+ if (maybe_msg) |msg| {
6322
+ try sema.mod.errNoteNonLazy(
6323
+ operand_ty.declSrcLoc(),
6324
+ msg,
6325
+ "error set '{}' declared here",
6326
+ .{operand_ty},
6327
+ );
6328
+ return sema.failWithOwnedErrorMsg(msg);
6329
+ }
6330
+
6331
+ if (special_prong == .@"else") {
6332
+ return sema.fail(
6333
+ block,
6334
+ special_prong_src,
6335
+ "unreachable else prong; all cases already handled",
6336
+ .{},
6337
+ );
6338
+ }
6339
+ }
6340
+ },
6255
6341
.Union => return sema.fail(block, src, "TODO validate switch .Union", .{}),
6256
6342
.Int, .ComptimeInt => {
6257
6343
var range_set = RangeSet.init(gpa);
@@ -6924,6 +7010,24 @@ fn validateSwitchItemEnum(
6924
7010
return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
6925
7011
}
6926
7012
7013
+ fn validateSwitchItemError(
7014
+ sema: *Sema,
7015
+ block: *Block,
7016
+ seen_errors: *SwitchErrorSet,
7017
+ item_ref: Zir.Inst.Ref,
7018
+ src_node_offset: i32,
7019
+ switch_prong_src: Module.SwitchProngSrc,
7020
+ ) CompileError!void {
7021
+ const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
7022
+ // TODO: Do i need to typecheck here?
7023
+ const error_name = item_tv.val.castTag(.@"error").?.data.name;
7024
+ const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev|
7025
+ prev.value
7026
+ else
7027
+ null;
7028
+ return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
7029
+ }
7030
+
6927
7031
fn validateSwitchDupe(
6928
7032
sema: *Sema,
6929
7033
block: *Block,
0 commit comments