| ... | ... | @@ -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, |