| ... | @@ -4826,26 +4826,8 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -4826,26 +4826,8 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 4826 | return Air.Inst.Ref.anyerror_type; | 4826 | return Air.Inst.Ref.anyerror_type; |
| 4827 | } | 4827 | } |
| 4828 | // Resolve both error sets now. | 4828 | // Resolve both error sets now. |
| 4829 | const lhs_names = switch (lhs_ty.tag()) { | 4829 | const lhs_names = lhs_ty.errorSetNames(); |
| 4830 | .error_set_single => blk: { | 4830 | const rhs_names = rhs_ty.errorSetNames(); |
| 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 | }; | | |
| 4849 | | 4831 | |
| 4850 | // TODO do we really want to create a Decl for this? | 4832 | // TODO do we really want to create a Decl for this? |
| 4851 | // The reason we do it right now is for memory management. | 4833 | // The reason we do it right now is for memory management. |
| ... | @@ -6080,6 +6062,8 @@ fn zirSwitchCond( | ... | @@ -6080,6 +6062,8 @@ fn zirSwitchCond( |
| 6080 | } | 6062 | } |
| 6081 | } | 6063 | } |
| 6082 | | 6064 | |
| | 6065 | const SwitchErrorSet = std.StringHashMap(Module.SwitchProngSrc); |
| | 6066 | |
| 6083 | fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 6067 | fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 6084 | const tracy = trace(@src()); | 6068 | const tracy = trace(@src()); |
| 6085 | defer tracy.end(); | 6069 | defer tracy.end(); |
| ... | @@ -6250,8 +6234,110 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -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 | .Union => return sema.fail(block, src, "TODO validate switch .Union", .{}), | 6341 | .Union => return sema.fail(block, src, "TODO validate switch .Union", .{}), |
| 6256 | .Int, .ComptimeInt => { | 6342 | .Int, .ComptimeInt => { |
| 6257 | var range_set = RangeSet.init(gpa); | 6343 | var range_set = RangeSet.init(gpa); |
| ... | @@ -6924,6 +7010,24 @@ fn validateSwitchItemEnum( | ... | @@ -6924,6 +7010,24 @@ fn validateSwitchItemEnum( |
| 6924 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); | 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 | fn validateSwitchDupe( | 7031 | fn validateSwitchDupe( |
| 6928 | sema: *Sema, | 7032 | sema: *Sema, |
| 6929 | block: *Block, | 7033 | block: *Block, |