| author | |
| committer | |
| log | ed1268d0e63d3af144a262a1fa41b8e69ab3073b |
| tree | 3f5e99ac159431271bc5c9029b6d8b9f8ee961b2 |
| parent | 8ec4c5cb137d9a93c35df3488408c44056c586b4 |
| signature |
5 files changed, 188 insertions(+), 390 deletions(-)
lib/std/zig/AstGen.zig+19-69| ... | @@ -7267,11 +7267,7 @@ fn switchExpr( | ... | @@ -7267,11 +7267,7 @@ fn switchExpr( |
| 7267 | var total_items_len: usize = 0; | 7267 | var total_items_len: usize = 0; |
| 7268 | var total_ranges_len: usize = 0; | 7268 | var total_ranges_len: usize = 0; |
| 7269 | var else_case_node: Ast.Node.OptionalIndex = .none; | 7269 | var else_case_node: Ast.Node.OptionalIndex = .none; |
| 7270 | var else_src: ?Ast.TokenIndex = null; | ||
| 7271 | var under_case_node: Ast.Node.OptionalIndex = .none; | ||
| 7272 | var underscore_node: Ast.Node.OptionalIndex = .none; | 7270 | var underscore_node: Ast.Node.OptionalIndex = .none; |
| 7273 | var underscore_src: ?Ast.TokenIndex = null; | ||
| 7274 | var under_is_bare = false; | ||
| 7275 | for (case_nodes) |case_node| { | 7271 | for (case_nodes) |case_node| { |
| 7276 | const case = tree.fullSwitchCase(case_node).?; | 7272 | const case = tree.fullSwitchCase(case_node).?; |
| 7277 | if (case.payload_token) |payload_token| { | 7273 | if (case.payload_token) |payload_token| { |
| ... | @@ -7304,22 +7300,21 @@ fn switchExpr( | ... | @@ -7304,22 +7300,21 @@ fn switchExpr( |
| 7304 | 7300 | ||
| 7305 | // Check for else prong. | 7301 | // Check for else prong. |
| 7306 | if (case.ast.values.len == 0) { | 7302 | if (case.ast.values.len == 0) { |
| 7307 | const case_src = case.ast.arrow_token - 1; | 7303 | if (else_case_node.unwrap()) |prev_case_node| { |
| 7308 | if (else_src) |src| { | 7304 | const prev_else_tok = tree.fullSwitchCase(prev_case_node).?.ast.arrow_token - 1; |
| 7305 | const else_tok = case.ast.arrow_token - 1; | ||
| 7309 | return astgen.failTokNotes( | 7306 | return astgen.failTokNotes( |
| 7310 | case_src, | 7307 | else_tok, |
| 7311 | "multiple else prongs in switch expression", | 7308 | "multiple else prongs in switch expression", |
| 7312 | .{}, | 7309 | .{}, |
| 7313 | &.{try astgen.errNoteTok(src, "previous else prong here", .{})}, | 7310 | &.{try astgen.errNoteTok(prev_else_tok, "previous else prong here", .{})}, |
| 7314 | ); | 7311 | ); |
| 7315 | } | 7312 | } |
| 7316 | else_case_node = case_node.toOptional(); | 7313 | else_case_node = case_node.toOptional(); |
| 7317 | else_src = case_src; | ||
| 7318 | continue; | 7314 | continue; |
| 7319 | } | 7315 | } |
| 7320 | 7316 | ||
| 7321 | // Check for '_' prong and ranges. | 7317 | // Check for '_' prong and ranges. |
| 7322 | var case_has_underscore = false; | ||
| 7323 | var case_has_ranges = false; | 7318 | var case_has_ranges = false; |
| 7324 | for (case.ast.values) |val| { | 7319 | for (case.ast.values) |val| { |
| 7325 | switch (tree.nodeTag(val)) { | 7320 | switch (tree.nodeTag(val)) { |
| ... | @@ -7329,10 +7324,10 @@ fn switchExpr( | ... | @@ -7329,10 +7324,10 @@ fn switchExpr( |
| 7329 | }, | 7324 | }, |
| 7330 | .string_literal => return astgen.failNode(val, "cannot switch on strings", .{}), | 7325 | .string_literal => return astgen.failNode(val, "cannot switch on strings", .{}), |
| 7331 | else => |tag| { | 7326 | else => |tag| { |
| 7327 | total_items_len += 1; | ||
| 7332 | if (tag == .identifier and | 7328 | if (tag == .identifier and |
| 7333 | mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(val)), "_")) | 7329 | mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(val)), "_")) |
| 7334 | { | 7330 | { |
| 7335 | const val_src = tree.nodeMainToken(val); | ||
| 7336 | if (is_err_switch) { | 7331 | if (is_err_switch) { |
| 7337 | const case_src = case.ast.arrow_token - 1; | 7332 | const case_src = case.ast.arrow_token - 1; |
| 7338 | return astgen.failTokNotes( | 7333 | return astgen.failTokNotes( |
| ... | @@ -7348,30 +7343,24 @@ fn switchExpr( | ... | @@ -7348,30 +7343,24 @@ fn switchExpr( |
| 7348 | }, | 7343 | }, |
| 7349 | ); | 7344 | ); |
| 7350 | } | 7345 | } |
| 7351 | if (underscore_src) |src| { | 7346 | if (underscore_node.unwrap()) |prev_src| { |
| 7352 | return astgen.failTokNotes( | 7347 | return astgen.failNodeNotes( |
| 7353 | val_src, | 7348 | val, |
| 7354 | "multiple '_' prongs in switch expression", | 7349 | "multiple '_' prongs in switch expression", |
| 7355 | .{}, | 7350 | .{}, |
| 7356 | &.{try astgen.errNoteTok(src, "previous '_' prong here", .{})}, | 7351 | &.{try astgen.errNoteNode(prev_src, "previous '_' prong here", .{})}, |
| 7357 | ); | 7352 | ); |
| 7358 | } | 7353 | } |
| 7359 | if (case.inline_token != null) { | 7354 | if (case.inline_token != null) { |
| 7360 | return astgen.failTok(val_src, "cannot inline '_' prong", .{}); | 7355 | return astgen.failNode(val, "cannot inline '_' prong", .{}); |
| 7361 | } | 7356 | } |
| 7362 | under_case_node = case_node.toOptional(); | ||
| 7363 | underscore_src = val_src; | ||
| 7364 | underscore_node = val.toOptional(); | 7357 | underscore_node = val.toOptional(); |
| 7365 | under_is_bare = case.ast.values.len == 1; | ||
| 7366 | case_has_underscore = true; | ||
| 7367 | } else { | ||
| 7368 | total_items_len += 1; | ||
| 7369 | } | 7358 | } |
| 7370 | }, | 7359 | }, |
| 7371 | } | 7360 | } |
| 7372 | } | 7361 | } |
| 7373 | 7362 | ||
| 7374 | const case_len = case.ast.values.len - @intFromBool(case_has_underscore); | 7363 | const case_len = case.ast.values.len; |
| 7375 | if (case_len == 1 and !case_has_ranges) { | 7364 | if (case_len == 1 and !case_has_ranges) { |
| 7376 | scalar_cases_len += 1; | 7365 | scalar_cases_len += 1; |
| 7377 | } else if (case_len >= 1) { | 7366 | } else if (case_len >= 1) { |
| ... | @@ -7379,9 +7368,8 @@ fn switchExpr( | ... | @@ -7379,9 +7368,8 @@ fn switchExpr( |
| 7379 | } | 7368 | } |
| 7380 | } | 7369 | } |
| 7381 | 7370 | ||
| 7382 | const has_else = else_src != null; | 7371 | const has_else = else_case_node != .none; |
| 7383 | const has_under = underscore_src != null; | 7372 | const has_under = underscore_node != .none; |
| 7384 | if (under_is_bare) assert(has_under); // make sure that the former implies the latter | ||
| 7385 | if (is_err_switch) assert(!has_under); // should have failed by now | 7373 | if (is_err_switch) assert(!has_under); // should have failed by now |
| 7386 | const any_ranges = total_ranges_len > 0; | 7374 | const any_ranges = total_ranges_len > 0; |
| 7387 | 7375 | ||
| ... | @@ -7430,10 +7418,8 @@ fn switchExpr( | ... | @@ -7430,10 +7418,8 @@ fn switchExpr( |
| 7430 | 7418 | ||
| 7431 | var non_err_prong_body_start: u32 = undefined; | 7419 | var non_err_prong_body_start: u32 = undefined; |
| 7432 | var else_prong_body_start: u32 = undefined; | 7420 | var else_prong_body_start: u32 = undefined; |
| 7433 | var bare_under_prong_body_start: u32 = undefined; | ||
| 7434 | var non_err_info: Zir.Inst.SwitchBlock.ProngInfo.NonErr = undefined; | 7421 | var non_err_info: Zir.Inst.SwitchBlock.ProngInfo.NonErr = undefined; |
| 7435 | var else_info: Zir.Inst.SwitchBlock.ProngInfo.Else = undefined; | 7422 | var else_info: Zir.Inst.SwitchBlock.ProngInfo.Else = undefined; |
| 7436 | var under_extra: u32 = undefined; | ||
| 7437 | 7423 | ||
| 7438 | var block_scope = parent_gz.makeSubBlock(scope); | 7424 | var block_scope = parent_gz.makeSubBlock(scope); |
| 7439 | // block_scope not used for collecting instructions | 7425 | // block_scope not used for collecting instructions |
| ... | @@ -7688,7 +7674,6 @@ fn switchExpr( | ... | @@ -7688,7 +7674,6 @@ fn switchExpr( |
| 7688 | for (case_nodes) |case_node| { | 7674 | for (case_nodes) |case_node| { |
| 7689 | const case = tree.fullSwitchCase(case_node).?; | 7675 | const case = tree.fullSwitchCase(case_node).?; |
| 7690 | 7676 | ||
| 7691 | const case_has_under = case_node.toOptional() == under_case_node; | ||
| 7692 | const ranges_len: u32 = if (any_ranges) blk: { | 7677 | const ranges_len: u32 = if (any_ranges) blk: { |
| 7693 | var ranges_len: u32 = 0; | 7678 | var ranges_len: u32 = 0; |
| 7694 | for (case.ast.values) |value| { | 7679 | for (case.ast.values) |value| { |
| ... | @@ -7696,14 +7681,13 @@ fn switchExpr( | ... | @@ -7696,14 +7681,13 @@ fn switchExpr( |
| 7696 | } | 7681 | } |
| 7697 | break :blk ranges_len; | 7682 | break :blk ranges_len; |
| 7698 | } else 0; | 7683 | } else 0; |
| 7699 | const items_len: u32 = @intCast(case.ast.values.len - ranges_len - @intFromBool(case_has_under)); | 7684 | const items_len: u32 = @intCast(case.ast.values.len - ranges_len); |
| 7700 | const is_multi_case = items_len > 1 or ranges_len > 0; | 7685 | const is_multi_case = items_len > 1 or ranges_len > 0; |
| 7701 | 7686 | ||
| 7702 | // item/range bodies in order of occurence | 7687 | // item/range bodies in order of occurence |
| 7703 | var item_i: usize = 0; | 7688 | var item_i: usize = 0; |
| 7704 | var range_i: usize = 0; | 7689 | var range_i: usize = 0; |
| 7705 | for (case.ast.values) |value| { | 7690 | for (case.ast.values) |value| { |
| 7706 | if (value.toOptional() == underscore_node) continue; | ||
| 7707 | const is_range = tree.nodeTag(value) == .switch_range; | 7691 | const is_range = tree.nodeTag(value) == .switch_range; |
| 7708 | const range: [2]Ast.Node.Index = if (is_range) tree.nodeData(value).node_and_node else undefined; | 7692 | const range: [2]Ast.Node.Index = if (is_range) tree.nodeData(value).node_and_node else undefined; |
| 7709 | const nodes: []const Ast.Node.Index = if (is_range) &range else &.{value}; | 7693 | const nodes: []const Ast.Node.Index = if (is_range) &range else &.{value}; |
| ... | @@ -7722,16 +7706,9 @@ fn switchExpr( | ... | @@ -7722,16 +7706,9 @@ fn switchExpr( |
| 7722 | const str_index = try astgen.identAsString(ident_token); | 7706 | const str_index = try astgen.identAsString(ident_token); |
| 7723 | break :blk .wrap(.{ .error_value = str_index }); | 7707 | break :blk .wrap(.{ .error_value = str_index }); |
| 7724 | }, | 7708 | }, |
| 7725 | .number_literal => { | 7709 | else => if (value.toOptional() == underscore_node) { |
| 7726 | // We don't actually need a final result type for number | 7710 | break :blk .wrap(.under); |
| 7727 | // literals, they can just be turned into `comptime_int` | 7711 | } else { |
| 7728 | // or `comptime_float` as usual and then be coerced to | ||
| 7729 | // the correct type later during semantic analysis. | ||
| 7730 | assert(scratch_scope.instructions_top == GenZir.unstacked_top); // important! we emit into `parent_gz` which `scratch_scope` is stacked on top of | ||
| 7731 | const zir_ref = try comptimeExpr(parent_gz, scope, .{ .rl = .none }, item, .switch_item); | ||
| 7732 | break :blk .wrap(.{ .number_literal = zir_ref }); | ||
| 7733 | }, | ||
| 7734 | else => { | ||
| 7735 | scratch_scope.instructions_top = parent_gz.instructions.items.len; | 7712 | scratch_scope.instructions_top = parent_gz.instructions.items.len; |
| 7736 | defer scratch_scope.unstack(); | 7713 | defer scratch_scope.unstack(); |
| 7737 | const item_result = try fullBodyExpr(&scratch_scope, scope, item_ri, item, .normal); | 7714 | const item_result = try fullBodyExpr(&scratch_scope, scope, item_ri, item, .normal); |
| ... | @@ -7957,25 +7934,6 @@ fn switchExpr( | ... | @@ -7957,25 +7934,6 @@ fn switchExpr( |
| 7957 | break :prong_body; | 7934 | break :prong_body; |
| 7958 | } | 7935 | } |
| 7959 | 7936 | ||
| 7960 | if (case_has_under) { | ||
| 7961 | // We're either writing under_prong_info or under_index here. | ||
| 7962 | if (under_is_bare) { | ||
| 7963 | assert(case.ast.values.len == 1); // only `_` | ||
| 7964 | const bare_under_info: Zir.Inst.SwitchBlock.ProngInfo.BareUnder = .{ | ||
| 7965 | .body_len = @intCast(body_len), | ||
| 7966 | .capture = capture, | ||
| 7967 | .has_tag_capture = has_tag_capture, | ||
| 7968 | }; | ||
| 7969 | under_extra = @bitCast(bare_under_info); | ||
| 7970 | bare_under_prong_body_start = body_start; | ||
| 7971 | break :prong_body; | ||
| 7972 | } else if (is_multi_case) { | ||
| 7973 | under_extra = scalar_cases_len + multi_case_index; | ||
| 7974 | } else { | ||
| 7975 | under_extra = scalar_case_index; | ||
| 7976 | } | ||
| 7977 | } | ||
| 7978 | |||
| 7979 | // We allow prongs with error items which are not inside the error set | 7937 | // We allow prongs with error items which are not inside the error set |
| 7980 | // being switched on if their body is `=> comptime unreachable,`. | 7938 | // being switched on if their body is `=> comptime unreachable,`. |
| 7981 | const is_comptime_unreach = comptime_unreach: { | 7939 | const is_comptime_unreach = comptime_unreach: { |
| ... | @@ -8003,7 +7961,7 @@ fn switchExpr( | ... | @@ -8003,7 +7961,7 @@ fn switchExpr( |
| 8003 | } | 7961 | } |
| 8004 | } | 7962 | } |
| 8005 | } | 7963 | } |
| 8006 | assert(scalar_case_index + multi_case_index + @intFromBool(has_else) + @intFromBool(under_is_bare) == case_nodes.len); | 7964 | assert(scalar_case_index + multi_case_index + @intFromBool(has_else) == case_nodes.len); |
| 8007 | assert(multi_items_infos_start + multi_item_offset == bodies_start); | 7965 | assert(multi_items_infos_start + multi_item_offset == bodies_start); |
| 8008 | 7966 | ||
| 8009 | if (switch_full.label_token) |label_token| if (!block_scope.label.?.used) { | 7967 | if (switch_full.label_token) |label_token| if (!block_scope.label.?.used) { |
| ... | @@ -8024,7 +7982,6 @@ fn switchExpr( | ... | @@ -8024,7 +7982,6 @@ fn switchExpr( |
| 8024 | @intFromBool(needs_non_err_handling) + // catch_or_if_src_node_offset | 7982 | @intFromBool(needs_non_err_handling) + // catch_or_if_src_node_offset |
| 8025 | @intFromBool(needs_non_err_handling) + // non_err_info | 7983 | @intFromBool(needs_non_err_handling) + // non_err_info |
| 8026 | @intFromBool(has_else) + // else_info | 7984 | @intFromBool(has_else) + // else_info |
| 8027 | @intFromBool(has_under) + // under_prong_info or under_index | ||
| 8028 | payloads.items.len - body_table_end); // item infos and bodies | 7985 | payloads.items.len - body_table_end); // item infos and bodies |
| 8029 | 7986 | ||
| 8030 | // singular pieces of data | 7987 | // singular pieces of data |
| ... | @@ -8035,7 +7992,6 @@ fn switchExpr( | ... | @@ -8035,7 +7992,6 @@ fn switchExpr( |
| 8035 | .any_ranges = any_ranges, | 7992 | .any_ranges = any_ranges, |
| 8036 | .has_else = has_else, | 7993 | .has_else = has_else, |
| 8037 | .has_under = has_under, | 7994 | .has_under = has_under, |
| 8038 | .under_is_bare = under_is_bare, | ||
| 8039 | .has_continue = switch_full.label_token != null and block_scope.label.?.used_for_continue, | 7995 | .has_continue = switch_full.label_token != null and block_scope.label.?.used_for_continue, |
| 8040 | .any_maybe_runtime_capture = any_maybe_runtime_capture, | 7996 | .any_maybe_runtime_capture = any_maybe_runtime_capture, |
| 8041 | .payload_capture_inst_is_placeholder = payload_capture_inst_is_placeholder, | 7997 | .payload_capture_inst_is_placeholder = payload_capture_inst_is_placeholder, |
| ... | @@ -8054,7 +8010,6 @@ fn switchExpr( | ... | @@ -8054,7 +8010,6 @@ fn switchExpr( |
| 8054 | astgen.extra.appendAssumeCapacity(@bitCast(non_err_info)); | 8010 | astgen.extra.appendAssumeCapacity(@bitCast(non_err_info)); |
| 8055 | } | 8011 | } |
| 8056 | if (has_else) astgen.extra.appendAssumeCapacity(@bitCast(else_info)); | 8012 | if (has_else) astgen.extra.appendAssumeCapacity(@bitCast(else_info)); |
| 8057 | if (has_under) astgen.extra.appendAssumeCapacity(under_extra); | ||
| 8058 | 8013 | ||
| 8059 | const extra_payloads_start = astgen.extra.items.len; | 8014 | const extra_payloads_start = astgen.extra.items.len; |
| 8060 | 8015 | ||
| ... | @@ -8070,11 +8025,6 @@ fn switchExpr( | ... | @@ -8070,11 +8025,6 @@ fn switchExpr( |
| 8070 | const body = payloads.items[else_prong_body_start..][0..else_info.body_len]; | 8025 | const body = payloads.items[else_prong_body_start..][0..else_info.body_len]; |
| 8071 | astgen.extra.appendSliceAssumeCapacity(body); | 8026 | astgen.extra.appendSliceAssumeCapacity(body); |
| 8072 | } | 8027 | } |
| 8073 | if (under_is_bare) { | ||
| 8074 | const under_prong_info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(under_extra); | ||
| 8075 | const body = payloads.items[bare_under_prong_body_start..][0..under_prong_info.body_len]; | ||
| 8076 | astgen.extra.appendSliceAssumeCapacity(body); | ||
| 8077 | } | ||
| 8078 | for (0..scalar_cases_len) |scalar_i| { | 8028 | for (0..scalar_cases_len) |scalar_i| { |
| 8079 | const item_info: Zir.Inst.SwitchBlock.ItemInfo = @bitCast(payloads.items[scalar_item_infos_start + scalar_i]); | 8029 | const item_info: Zir.Inst.SwitchBlock.ItemInfo = @bitCast(payloads.items[scalar_item_infos_start + scalar_i]); |
| 8080 | const item_body_start = payloads.items[scalar_body_table + scalar_i]; | 8030 | const item_body_start = payloads.items[scalar_body_table + scalar_i]; |
lib/std/zig/Zir.zig+19-104| ... | @@ -3303,34 +3303,25 @@ pub const Inst = struct { | ... | @@ -3303,34 +3303,25 @@ pub const Inst = struct { |
| 3303 | /// 3. catch_or_if_src_node_offset: Ast.Node.Offset, // If inst is switch_block_err_union. | 3303 | /// 3. catch_or_if_src_node_offset: Ast.Node.Offset, // If inst is switch_block_err_union. |
| 3304 | /// 4. non_err_info: ProngInfo.NonErr, // If inst is switch_block_err_union. | 3304 | /// 4. non_err_info: ProngInfo.NonErr, // If inst is switch_block_err_union. |
| 3305 | /// 5. else_info: ProngInfo.Else, // If has_else is set. | 3305 | /// 5. else_info: ProngInfo.Else, // If has_else is set. |
| 3306 | /// 6. under_info: ProngInfo.Under, // If has_under is set and | 3306 | /// 6. scalar_prong_info: ProngInfo, // for every scalar_cases_len |
| 3307 | /// // under_is_bare is set. | 3307 | /// 7. multi_prong_info: ProngInfo, // for every multi_cases_len |
| 3308 | /// 7. under_index: u32, // If has_under is set and | 3308 | /// 8. multi_case_items_len: u32, // for every multi_cases_len |
| 3309 | /// // under_is_bare is *not* set. | 3309 | /// 9. multi_case_ranges_len: u32, // If has_ranges is set: for every multi_cases_len |
| 3310 | /// // Index into switch cases. | 3310 | /// 10. scalar_item_info: ItemInfo, // for every scalar_cases_len |
| 3311 | /// 8. scalar_prong_info: ProngInfo, // for every scalar_cases_len | 3311 | /// 11. multi_items_info: { // for every multi_cases_len |
| 3312 | /// 9. multi_prong_info: ProngInfo, // for every multi_cases_len | ||
| 3313 | /// 10. multi_case_items_len: u32, // for every multi_cases_len | ||
| 3314 | /// 11. multi_case_ranges_len: u32, // If has_ranges is set: for every multi_cases_len | ||
| 3315 | /// 12. scalar_item_info: ItemInfo, // for every scalar_cases_len | ||
| 3316 | /// 13. multi_items_info: { // for every multi_cases_len | ||
| 3317 | /// item_info: ItemInfo, // for each multi_case_items_len | 3312 | /// item_info: ItemInfo, // for each multi_case_items_len |
| 3318 | /// range_items_info: { // for each multi_case_ranges_len | 3313 | /// range_items_info: { // for each multi_case_ranges_len |
| 3319 | /// first_info: ItemInfo, | 3314 | /// first_info: ItemInfo, |
| 3320 | /// last_info: ItemInfo, | 3315 | /// last_info: ItemInfo, |
| 3321 | /// } | 3316 | /// } |
| 3322 | /// } | 3317 | /// } |
| 3323 | /// 14. non_err_body { | 3318 | /// 12. non_err_body { |
| 3324 | /// body_inst: Index // for every non_err_info.body_len | 3319 | /// body_inst: Index // for every non_err_info.body_len |
| 3325 | /// } | 3320 | /// } |
| 3326 | /// 15. else_body: { // If has_else is set. | 3321 | /// 13. else_body: { // If has_else is set. |
| 3327 | /// body_inst: Inst.Index, // for every else_info.body_len | 3322 | /// body_inst: Inst.Index, // for every else_info.body_len |
| 3328 | /// } | 3323 | /// } |
| 3329 | /// 16. under_body: { // If has_under is set and | 3324 | /// 14. scalar_bodies: { // for every scalar_cases_len |
| 3330 | /// // under_is_bare is set. | ||
| 3331 | /// body_inst: Inst.Index, // for every under_info.body_len | ||
| 3332 | /// } | ||
| 3333 | /// 17. scalar_bodies: { // for every scalar_cases_len | ||
| 3334 | /// prong_body: { // for each body_len in scalar_prong_info | 3325 | /// prong_body: { // for each body_len in scalar_prong_info |
| 3335 | /// body_inst: Inst.Index, // for every body_len | 3326 | /// body_inst: Inst.Index, // for every body_len |
| 3336 | /// } | 3327 | /// } |
| ... | @@ -3338,7 +3329,7 @@ pub const Inst = struct { | ... | @@ -3338,7 +3329,7 @@ pub const Inst = struct { |
| 3338 | /// body_inst: Inst.Index, // for every body_len | 3329 | /// body_inst: Inst.Index, // for every body_len |
| 3339 | /// } | 3330 | /// } |
| 3340 | /// } | 3331 | /// } |
| 3341 | /// 18. multi_bodies: { // for each multi_items_info | 3332 | /// 15. multi_bodies: { // for each multi_items_info |
| 3342 | /// prong_body: { | 3333 | /// prong_body: { |
| 3343 | /// body_inst: Inst.Index, // for each multi_prong_info.body_len | 3334 | /// body_inst: Inst.Index, // for each multi_prong_info.body_len |
| 3344 | /// } | 3335 | /// } |
| ... | @@ -3363,8 +3354,6 @@ pub const Inst = struct { | ... | @@ -3363,8 +3354,6 @@ pub const Inst = struct { |
| 3363 | any_ranges: bool, | 3354 | any_ranges: bool, |
| 3364 | has_else: bool, | 3355 | has_else: bool, |
| 3365 | has_under: bool, | 3356 | has_under: bool, |
| 3366 | /// Only valid if `has_under` is also set. | ||
| 3367 | under_is_bare: bool, | ||
| 3368 | /// If true, at least one prong contains a `continue`. | 3357 | /// If true, at least one prong contains a `continue`. |
| 3369 | /// Only valid if `has_label` is set. | 3358 | /// Only valid if `has_label` is set. |
| 3370 | has_continue: bool, | 3359 | has_continue: bool, |
| ... | @@ -3377,7 +3366,7 @@ pub const Inst = struct { | ... | @@ -3377,7 +3366,7 @@ pub const Inst = struct { |
| 3377 | // NOTE maybe don't steal any more bits from poor `scalar_cases_len` | 3366 | // NOTE maybe don't steal any more bits from poor `scalar_cases_len` |
| 3378 | // and split `Bits` into two parts instead, `raw_operand` surely | 3367 | // and split `Bits` into two parts instead, `raw_operand` surely |
| 3379 | // wouldn't mind donating a couple of bits for that purpose... | 3368 | // wouldn't mind donating a couple of bits for that purpose... |
| 3380 | pub const ScalarCasesLen = u23; | 3369 | pub const ScalarCasesLen = u24; |
| 3381 | }; | 3370 | }; |
| 3382 | 3371 | ||
| 3383 | pub const ProngInfo = packed struct(u32) { | 3372 | pub const ProngInfo = packed struct(u32) { |
| ... | @@ -3406,12 +3395,6 @@ pub const Inst = struct { | ... | @@ -3406,12 +3395,6 @@ pub const Inst = struct { |
| 3406 | has_tag_capture: bool, | 3395 | has_tag_capture: bool, |
| 3407 | is_simple_noreturn: bool, | 3396 | is_simple_noreturn: bool, |
| 3408 | }; | 3397 | }; |
| 3409 | |||
| 3410 | pub const BareUnder = packed struct(u32) { | ||
| 3411 | body_len: u29, | ||
| 3412 | capture: ProngInfo.Capture, | ||
| 3413 | has_tag_capture: bool, | ||
| 3414 | }; | ||
| 3415 | }; | 3398 | }; |
| 3416 | 3399 | ||
| 3417 | pub const ItemInfo = packed struct(u32) { | 3400 | pub const ItemInfo = packed struct(u32) { |
| ... | @@ -3421,23 +3404,23 @@ pub const Inst = struct { | ... | @@ -3421,23 +3404,23 @@ pub const Inst = struct { |
| 3421 | pub const Kind = enum(u2) { | 3404 | pub const Kind = enum(u2) { |
| 3422 | enum_literal, | 3405 | enum_literal, |
| 3423 | error_value, | 3406 | error_value, |
| 3424 | number_literal, | ||
| 3425 | body_len, | 3407 | body_len, |
| 3408 | under, | ||
| 3426 | }; | 3409 | }; |
| 3427 | 3410 | ||
| 3428 | pub const Unwrapped = union(ItemInfo.Kind) { | 3411 | pub const Unwrapped = union(ItemInfo.Kind) { |
| 3429 | enum_literal: Zir.NullTerminatedString, | 3412 | enum_literal: Zir.NullTerminatedString, |
| 3430 | error_value: Zir.NullTerminatedString, | 3413 | error_value: Zir.NullTerminatedString, |
| 3431 | number_literal: Inst.Ref, | ||
| 3432 | body_len: u32, | 3414 | body_len: u32, |
| 3415 | under, | ||
| 3433 | }; | 3416 | }; |
| 3434 | 3417 | ||
| 3435 | pub fn wrap(unwrapped: ItemInfo.Unwrapped) ItemInfo { | 3418 | pub fn wrap(unwrapped: ItemInfo.Unwrapped) ItemInfo { |
| 3436 | const data_uncasted: u32 = switch (unwrapped) { | 3419 | const data_uncasted: u32 = switch (unwrapped) { |
| 3437 | .enum_literal => |str_index| @intFromEnum(str_index), | 3420 | .enum_literal => |str_index| @intFromEnum(str_index), |
| 3438 | .error_value => |str_index| @intFromEnum(str_index), | 3421 | .error_value => |str_index| @intFromEnum(str_index), |
| 3439 | .number_literal => |zir_ref| @intFromEnum(zir_ref), | ||
| 3440 | .body_len => |body_len| body_len, | 3422 | .body_len => |body_len| body_len, |
| 3423 | .under => 0, | ||
| 3441 | }; | 3424 | }; |
| 3442 | return .{ .kind = unwrapped, .data = @intCast(data_uncasted) }; | 3425 | return .{ .kind = unwrapped, .data = @intCast(data_uncasted) }; |
| 3443 | } | 3426 | } |
| ... | @@ -3446,8 +3429,8 @@ pub const Inst = struct { | ... | @@ -3446,8 +3429,8 @@ pub const Inst = struct { |
| 3446 | return switch (item_info.kind) { | 3429 | return switch (item_info.kind) { |
| 3447 | .enum_literal => .{ .enum_literal = @enumFromInt(item_info.data) }, | 3430 | .enum_literal => .{ .enum_literal = @enumFromInt(item_info.data) }, |
| 3448 | .error_value => .{ .error_value = @enumFromInt(item_info.data) }, | 3431 | .error_value => .{ .error_value = @enumFromInt(item_info.data) }, |
| 3449 | .number_literal => .{ .number_literal = @enumFromInt(item_info.data) }, | ||
| 3450 | .body_len => .{ .body_len = item_info.data }, | 3432 | .body_len => .{ .body_len = item_info.data }, |
| 3433 | .under => .under, | ||
| 3451 | }; | 3434 | }; |
| 3452 | } | 3435 | } |
| 3453 | 3436 | ||
| ... | @@ -4818,9 +4801,6 @@ fn findTrackableInner( | ... | @@ -4818,9 +4801,6 @@ fn findTrackableInner( |
| 4818 | if (zir_switch.else_case) |else_case| { | 4801 | if (zir_switch.else_case) |else_case| { |
| 4819 | try zir.findTrackableBody(gpa, contents, defers, else_case.body); | 4802 | try zir.findTrackableBody(gpa, contents, defers, else_case.body); |
| 4820 | } | 4803 | } |
| 4821 | if (zir_switch.under_case.resolve()) |under_case| { | ||
| 4822 | try zir.findTrackableBody(gpa, contents, defers, under_case.body); | ||
| 4823 | } | ||
| 4824 | var extra_index = zir_switch.end; | 4804 | var extra_index = zir_switch.end; |
| 4825 | var case_it = zir_switch.iterateCases(); | 4805 | var case_it = zir_switch.iterateCases(); |
| 4826 | while (case_it.next()) |case| { | 4806 | while (case_it.next()) |case| { |
| ... | @@ -5268,16 +5248,6 @@ pub fn getSwitchBlock(zir: *const Zir, switch_inst: Inst.Index) UnwrappedSwitchB | ... | @@ -5268,16 +5248,6 @@ pub fn getSwitchBlock(zir: *const Zir, switch_inst: Inst.Index) UnwrappedSwitchB |
| 5268 | extra_index += 1; | 5248 | extra_index += 1; |
| 5269 | break :else_info else_info; | 5249 | break :else_info else_info; |
| 5270 | } else undefined; | 5250 | } else undefined; |
| 5271 | const bare_under_info: Inst.SwitchBlock.ProngInfo.BareUnder = if (bits.has_under and bits.under_is_bare) bare_under_info: { | ||
| 5272 | const bare_under_info: Inst.SwitchBlock.ProngInfo.BareUnder = @bitCast(zir.extra[extra_index]); | ||
| 5273 | extra_index += 1; | ||
| 5274 | break :bare_under_info bare_under_info; | ||
| 5275 | } else undefined; | ||
| 5276 | const under_index: u32 = if (bits.has_under and !bits.under_is_bare) under_index: { | ||
| 5277 | const under_index = zir.extra[extra_index]; | ||
| 5278 | extra_index += 1; | ||
| 5279 | break :under_index under_index; | ||
| 5280 | } else undefined; | ||
| 5281 | const scalar_cases_len: u32 = bits.scalar_cases_len; | 5251 | const scalar_cases_len: u32 = bits.scalar_cases_len; |
| 5282 | const prong_infos: []const Inst.SwitchBlock.ProngInfo = | 5252 | const prong_infos: []const Inst.SwitchBlock.ProngInfo = |
| 5283 | @ptrCast(zir.extra[extra_index..][0 .. scalar_cases_len + multi_cases_len]); | 5253 | @ptrCast(zir.extra[extra_index..][0 .. scalar_cases_len + multi_cases_len]); |
| ... | @@ -5320,20 +5290,6 @@ pub fn getSwitchBlock(zir: *const Zir, switch_inst: Inst.Index) UnwrappedSwitchB | ... | @@ -5320,20 +5290,6 @@ pub fn getSwitchBlock(zir: *const Zir, switch_inst: Inst.Index) UnwrappedSwitchB |
| 5320 | .is_simple_noreturn = else_info.is_simple_noreturn, | 5290 | .is_simple_noreturn = else_info.is_simple_noreturn, |
| 5321 | }; | 5291 | }; |
| 5322 | } else null; | 5292 | } else null; |
| 5323 | const under_case: UnwrappedSwitchBlock.Case.Under = if (bits.has_under) under_case: { | ||
| 5324 | if (bits.under_is_bare) { | ||
| 5325 | const body = zir.bodySlice(extra_index, bare_under_info.body_len); | ||
| 5326 | extra_index += body.len; | ||
| 5327 | break :under_case .{ .bare = .{ | ||
| 5328 | .index = .bare_under, | ||
| 5329 | .body = body, | ||
| 5330 | .capture = bare_under_info.capture, | ||
| 5331 | .has_tag_capture = bare_under_info.has_tag_capture, | ||
| 5332 | } }; | ||
| 5333 | } else { | ||
| 5334 | break :under_case .{ .index = under_index }; | ||
| 5335 | } | ||
| 5336 | } else .none; | ||
| 5337 | return .{ | 5293 | return .{ |
| 5338 | .main_operand = extra.data.raw_operand, | 5294 | .main_operand = extra.data.raw_operand, |
| 5339 | .switch_src_node_offset = inst_data.src_node, | 5295 | .switch_src_node_offset = inst_data.src_node, |
| ... | @@ -5344,7 +5300,7 @@ pub fn getSwitchBlock(zir: *const Zir, switch_inst: Inst.Index) UnwrappedSwitchB | ... | @@ -5344,7 +5300,7 @@ pub fn getSwitchBlock(zir: *const Zir, switch_inst: Inst.Index) UnwrappedSwitchB |
| 5344 | .any_maybe_runtime_capture = bits.any_maybe_runtime_capture, | 5300 | .any_maybe_runtime_capture = bits.any_maybe_runtime_capture, |
| 5345 | .non_err_case = non_err_case, | 5301 | .non_err_case = non_err_case, |
| 5346 | .else_case = else_case, | 5302 | .else_case = else_case, |
| 5347 | .under_case = under_case, | 5303 | .has_under = bits.has_under, |
| 5348 | .prong_infos = prong_infos, | 5304 | .prong_infos = prong_infos, |
| 5349 | .multi_case_items_lens = multi_case_items_lens, | 5305 | .multi_case_items_lens = multi_case_items_lens, |
| 5350 | .multi_case_ranges_lens = multi_case_ranges_lens, | 5306 | .multi_case_ranges_lens = multi_case_ranges_lens, |
| ... | @@ -5377,7 +5333,7 @@ pub const UnwrappedSwitchBlock = struct { | ... | @@ -5377,7 +5333,7 @@ pub const UnwrappedSwitchBlock = struct { |
| 5377 | any_maybe_runtime_capture: bool, | 5333 | any_maybe_runtime_capture: bool, |
| 5378 | non_err_case: ?Case.NonErr, | 5334 | non_err_case: ?Case.NonErr, |
| 5379 | else_case: ?Case.Else, | 5335 | else_case: ?Case.Else, |
| 5380 | under_case: Case.Under, | 5336 | has_under: bool, |
| 5381 | // Refer to doc comment and `iterateCases` to access everything below correctly. | 5337 | // Refer to doc comment and `iterateCases` to access everything below correctly. |
| 5382 | prong_infos: []const Inst.SwitchBlock.ProngInfo, | 5338 | prong_infos: []const Inst.SwitchBlock.ProngInfo, |
| 5383 | multi_case_items_lens: []const u32, | 5339 | multi_case_items_lens: []const u32, |
| ... | @@ -5411,25 +5367,13 @@ pub const UnwrappedSwitchBlock = struct { | ... | @@ -5411,25 +5367,13 @@ pub const UnwrappedSwitchBlock = struct { |
| 5411 | item_infos: []const Inst.SwitchBlock.ItemInfo, | 5367 | item_infos: []const Inst.SwitchBlock.ItemInfo, |
| 5412 | range_infos: []const [2]Inst.SwitchBlock.ItemInfo, | 5368 | range_infos: []const [2]Inst.SwitchBlock.ItemInfo, |
| 5413 | 5369 | ||
| 5414 | pub fn isUnder(case: *const Case) bool { | ||
| 5415 | return case.index.is_under; | ||
| 5416 | } | ||
| 5417 | |||
| 5418 | pub const Index = packed struct(u32) { | 5370 | pub const Index = packed struct(u32) { |
| 5419 | kind: enum(u1) { scalar, multi }, | 5371 | kind: enum(u1) { scalar, multi }, |
| 5420 | is_under: bool, | 5372 | value: u31, |
| 5421 | value: u30, | ||
| 5422 | 5373 | ||
| 5423 | pub const @"else": Case.Index = .{ | 5374 | pub const @"else": Case.Index = .{ |
| 5424 | .kind = .scalar, | 5375 | .kind = .scalar, |
| 5425 | .is_under = false, | 5376 | .value = std.math.maxInt(u31), |
| 5426 | .value = std.math.maxInt(u30), | ||
| 5427 | }; | ||
| 5428 | |||
| 5429 | pub const bare_under: Case.Index = .{ | ||
| 5430 | .kind = .scalar, | ||
| 5431 | .is_under = true, | ||
| 5432 | .value = std.math.maxInt(u30), | ||
| 5433 | }; | 5377 | }; |
| 5434 | }; | 5378 | }; |
| 5435 | 5379 | ||
| ... | @@ -5448,31 +5392,8 @@ pub const UnwrappedSwitchBlock = struct { | ... | @@ -5448,31 +5392,8 @@ pub const UnwrappedSwitchBlock = struct { |
| 5448 | is_simple_noreturn: bool, | 5392 | is_simple_noreturn: bool, |
| 5449 | }; | 5393 | }; |
| 5450 | 5394 | ||
| 5451 | pub const Under = union(enum) { | ||
| 5452 | none, | ||
| 5453 | bare: Under.Resolved, | ||
| 5454 | index: u32, | ||
| 5455 | |||
| 5456 | pub const Resolved = struct { | ||
| 5457 | index: Case.Index, | ||
| 5458 | body: []const Inst.Index, | ||
| 5459 | capture: Inst.SwitchBlock.ProngInfo.Capture, | ||
| 5460 | has_tag_capture: bool, | ||
| 5461 | }; | ||
| 5462 | |||
| 5463 | /// If this returns `null` and `under` is not `.none`, you'll have to | ||
| 5464 | /// find the under case by iterating all cases and using `isUnder`! | ||
| 5465 | pub fn resolve(under: Under) ?Under.Resolved { | ||
| 5466 | return switch (under) { | ||
| 5467 | .bare => |resolved| resolved, | ||
| 5468 | .none, .index => null, | ||
| 5469 | }; | ||
| 5470 | } | ||
| 5471 | }; | ||
| 5472 | |||
| 5473 | pub const Iterator = struct { | 5395 | pub const Iterator = struct { |
| 5474 | next_idx: u32, | 5396 | next_idx: u32, |
| 5475 | under_idx: ?u32, | ||
| 5476 | prong_infos: []const Inst.SwitchBlock.ProngInfo, | 5397 | prong_infos: []const Inst.SwitchBlock.ProngInfo, |
| 5477 | multi_case_items_lens: []const u32, | 5398 | multi_case_items_lens: []const u32, |
| 5478 | multi_case_ranges_lens: ?[]const u32, | 5399 | multi_case_ranges_lens: ?[]const u32, |
| ... | @@ -5486,7 +5407,6 @@ pub const UnwrappedSwitchBlock = struct { | ... | @@ -5486,7 +5407,6 @@ pub const UnwrappedSwitchBlock = struct { |
| 5486 | return if (idx < scalar_cases_len) .{ | 5407 | return if (idx < scalar_cases_len) .{ |
| 5487 | .index = .{ | 5408 | .index = .{ |
| 5488 | .kind = .scalar, | 5409 | .kind = .scalar, |
| 5489 | .is_under = idx == it.under_idx, | ||
| 5490 | .value = @intCast(idx), | 5410 | .value = @intCast(idx), |
| 5491 | }, | 5411 | }, |
| 5492 | .prong_info = it.prong_infos[idx], | 5412 | .prong_info = it.prong_infos[idx], |
| ... | @@ -5495,7 +5415,6 @@ pub const UnwrappedSwitchBlock = struct { | ... | @@ -5495,7 +5415,6 @@ pub const UnwrappedSwitchBlock = struct { |
| 5495 | } else .{ | 5415 | } else .{ |
| 5496 | .index = .{ | 5416 | .index = .{ |
| 5497 | .kind = .multi, | 5417 | .kind = .multi, |
| 5498 | .is_under = idx == it.under_idx, | ||
| 5499 | .value = @intCast(idx - scalar_cases_len), | 5418 | .value = @intCast(idx - scalar_cases_len), |
| 5500 | }, | 5419 | }, |
| 5501 | .prong_info = it.prong_infos[idx], | 5420 | .prong_info = it.prong_infos[idx], |
| ... | @@ -5516,10 +5435,6 @@ pub const UnwrappedSwitchBlock = struct { | ... | @@ -5516,10 +5435,6 @@ pub const UnwrappedSwitchBlock = struct { |
| 5516 | pub fn iterateCases(unwrapped: UnwrappedSwitchBlock) Case.Iterator { | 5435 | pub fn iterateCases(unwrapped: UnwrappedSwitchBlock) Case.Iterator { |
| 5517 | return .{ | 5436 | return .{ |
| 5518 | .next_idx = 0, | 5437 | .next_idx = 0, |
| 5519 | .under_idx = switch (unwrapped.under_case) { | ||
| 5520 | .none, .bare => null, | ||
| 5521 | .index => |index| index, | ||
| 5522 | }, | ||
| 5523 | .prong_infos = unwrapped.prong_infos, | 5438 | .prong_infos = unwrapped.prong_infos, |
| 5524 | .multi_case_items_lens = unwrapped.multi_case_items_lens, | 5439 | .multi_case_items_lens = unwrapped.multi_case_items_lens, |
| 5525 | .multi_case_ranges_lens = unwrapped.multi_case_ranges_lens, | 5440 | .multi_case_ranges_lens = unwrapped.multi_case_ranges_lens, |
src/Sema.zig+112-129| ... | @@ -10753,10 +10753,9 @@ fn analyzeSwitchBlock( | ... | @@ -10753,10 +10753,9 @@ fn analyzeSwitchBlock( |
| 10753 | const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset }); | 10753 | const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset }); |
| 10754 | 10754 | ||
| 10755 | const has_else = zir_switch.else_case != null; | 10755 | const has_else = zir_switch.else_case != null; |
| 10756 | const has_under = zir_switch.under_case != .none; | 10756 | const has_under = zir_switch.has_under; |
| 10757 | 10757 | ||
| 10758 | const else_case = validated_switch.else_case; | 10758 | const else_case = validated_switch.else_case; |
| 10759 | const under_case = validated_switch.under_case; | ||
| 10760 | 10759 | ||
| 10761 | const operand: SwitchOperand, const operand_ty: Type, const maybe_operand_opv: ?Value, const item_ty: Type = operand: { | 10760 | const operand: SwitchOperand, const operand_ty: Type, const maybe_operand_opv: ?Value, const item_ty: Type = operand: { |
| 10762 | const val, const ref = if (operand_is_ref) | 10761 | const val, const ref = if (operand_is_ref) |
| ... | @@ -10933,9 +10932,6 @@ fn analyzeSwitchBlock( | ... | @@ -10933,9 +10932,6 @@ fn analyzeSwitchBlock( |
| 10933 | // we allow simple noreturn else prongs when switching on error sets! | 10932 | // we allow simple noreturn else prongs when switching on error sets! |
| 10934 | break :find_prong .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture, else_case.is_inline, true }; | 10933 | break :find_prong .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture, else_case.is_inline, true }; |
| 10935 | } | 10934 | } |
| 10936 | if (has_under) { | ||
| 10937 | break :find_prong .{ under_case.index, under_case.body, under_case.capture, under_case.has_tag_capture, false, true }; | ||
| 10938 | } | ||
| 10939 | unreachable; // malformed validated switch | 10935 | unreachable; // malformed validated switch |
| 10940 | }; | 10936 | }; |
| 10941 | 10937 | ||
| ... | @@ -11083,10 +11079,9 @@ fn finishSwitchBr( | ... | @@ -11083,10 +11079,9 @@ fn finishSwitchBr( |
| 11083 | const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset }); | 11079 | const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset }); |
| 11084 | 11080 | ||
| 11085 | const has_else = zir_switch.else_case != null; | 11081 | const has_else = zir_switch.else_case != null; |
| 11086 | const has_under = zir_switch.under_case != .none; | 11082 | const has_under = zir_switch.has_under; |
| 11087 | 11083 | ||
| 11088 | const else_case = validated_switch.else_case; | 11084 | const else_case = validated_switch.else_case; |
| 11089 | const under_case = validated_switch.under_case; | ||
| 11090 | 11085 | ||
| 11091 | const scalar_cases_len = zir_switch.scalarCasesLen(); | 11086 | const scalar_cases_len = zir_switch.scalarCasesLen(); |
| 11092 | const multi_cases_len = zir_switch.multiCasesLen(); | 11087 | const multi_cases_len = zir_switch.multiCasesLen(); |
| ... | @@ -11138,20 +11133,15 @@ fn finishSwitchBr( | ... | @@ -11138,20 +11133,15 @@ fn finishSwitchBr( |
| 11138 | var case_it = zir_switch.iterateCases(); | 11133 | var case_it = zir_switch.iterateCases(); |
| 11139 | var extra_index = zir_switch.end; | 11134 | var extra_index = zir_switch.end; |
| 11140 | 11135 | ||
| 11136 | var under_prong: ?struct { | ||
| 11137 | index: Zir.UnwrappedSwitchBlock.Case.Index, | ||
| 11138 | body: []const Zir.Inst.Index, | ||
| 11139 | capture: Zir.Inst.SwitchBlock.ProngInfo.Capture, | ||
| 11140 | has_tag_capture: bool, | ||
| 11141 | } = null; | ||
| 11142 | |||
| 11141 | var cases_len: u32 = 0; | 11143 | var cases_len: u32 = 0; |
| 11142 | while (case_it.next()) |case| { | 11144 | while (case_it.next()) |case| { |
| 11143 | if (case.isUnder()) { // we'll deal with this later | ||
| 11144 | extra_index += case.prong_info.body_len; | ||
| 11145 | for (case.item_infos) |item_info| { | ||
| 11146 | if (item_info.bodyLen()) |body_len| extra_index += body_len; | ||
| 11147 | } | ||
| 11148 | for (case.range_infos) |range_info| { | ||
| 11149 | if (range_info[0].bodyLen()) |body_len| extra_index += body_len; | ||
| 11150 | if (range_info[1].bodyLen()) |body_len| extra_index += body_len; | ||
| 11151 | } | ||
| 11152 | continue; | ||
| 11153 | } | ||
| 11154 | |||
| 11155 | const item_refs = case_vals[case_val_idx..][0..case.item_infos.len]; | 11145 | const item_refs = case_vals[case_val_idx..][0..case.item_infos.len]; |
| 11156 | case_val_idx += item_refs.len; | 11146 | case_val_idx += item_refs.len; |
| 11157 | const range_refs: []const [2]Air.Inst.Ref = | 11147 | const range_refs: []const [2]Air.Inst.Ref = |
| ... | @@ -11171,7 +11161,9 @@ fn finishSwitchBr( | ... | @@ -11171,7 +11161,9 @@ fn finishSwitchBr( |
| 11171 | 11161 | ||
| 11172 | var emit_bb = false; | 11162 | var emit_bb = false; |
| 11173 | var any_analyze_body = false; | 11163 | var any_analyze_body = false; |
| 11164 | var is_under_prong = false; | ||
| 11174 | for (case.item_infos, item_refs, 0..) |item_info, item_ref, item_i| { | 11165 | for (case.item_infos, item_refs, 0..) |item_info, item_ref, item_i| { |
| 11166 | if (item_ref == .none) is_under_prong = true; | ||
| 11175 | if (item_info.bodyLen()) |body_len| extra_index += body_len; | 11167 | if (item_info.bodyLen()) |body_len| extra_index += body_len; |
| 11176 | 11168 | ||
| 11177 | const analyze_body = sema.wantSwitchProngBodyAnalysis(block, item_ref, operand_ty, union_originally, err_set, prong_info.is_comptime_unreach); | 11169 | const analyze_body = sema.wantSwitchProngBodyAnalysis(block, item_ref, operand_ty, union_originally, err_set, prong_info.is_comptime_unreach); |
| ... | @@ -11319,48 +11311,58 @@ fn finishSwitchBr( | ... | @@ -11319,48 +11311,58 @@ fn finishSwitchBr( |
| 11319 | } | 11311 | } |
| 11320 | } | 11312 | } |
| 11321 | 11313 | ||
| 11322 | if (!prong_info.is_inline) { | 11314 | if (prong_info.is_inline) continue; // handled above |
| 11323 | cases_len += 1; | ||
| 11324 | case_block.instructions.clearRetainingCapacity(); | ||
| 11325 | case_block.error_return_trace_index = child_block.error_return_trace_index; | ||
| 11326 | 11315 | ||
| 11327 | const prong_hint: std.builtin.BranchHint = hint: { | 11316 | if (is_under_prong) { |
| 11328 | if (any_analyze_body) break :hint try sema.analyzeSwitchProng( | 11317 | under_prong = .{ |
| 11329 | &case_block, | 11318 | .index = case.index, |
| 11330 | operand, | 11319 | .body = prong_body, |
| 11331 | operand_ty, | 11320 | .capture = case.prong_info.capture, |
| 11332 | raw_operand_ty, | 11321 | .has_tag_capture = case.prong_info.has_tag_capture, |
| 11333 | prong_body, | ||
| 11334 | block.src(.{ .switch_capture = .{ | ||
| 11335 | .switch_node_offset = src_node_offset, | ||
| 11336 | .case_idx = case.index, | ||
| 11337 | } }), | ||
| 11338 | prong_info.capture, | ||
| 11339 | prong_info.has_tag_capture, | ||
| 11340 | .none, | ||
| 11341 | .{ .item_refs = item_refs }, | ||
| 11342 | validated_switch.else_err_ty, | ||
| 11343 | switch_inst, | ||
| 11344 | zir_switch, | ||
| 11345 | ); | ||
| 11346 | _ = try case_block.addNoOp(.unreach); | ||
| 11347 | break :hint .cold; // unreachable branches are cold | ||
| 11348 | }; | 11322 | }; |
| 11349 | try branch_hints.append(gpa, prong_hint); | 11323 | continue; |
| 11350 | |||
| 11351 | try cases_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr.Case).@"struct".fields.len + | ||
| 11352 | item_refs.len + | ||
| 11353 | 2 * range_refs.len + | ||
| 11354 | case_block.instructions.items.len); | ||
| 11355 | cases_extra.appendSliceAssumeCapacity(&payloadToExtraItems(Air.SwitchBr.Case{ | ||
| 11356 | .items_len = @intCast(item_refs.len), | ||
| 11357 | .ranges_len = @intCast(range_refs.len), | ||
| 11358 | .body_len = @intCast(case_block.instructions.items.len), | ||
| 11359 | })); | ||
| 11360 | cases_extra.appendSliceAssumeCapacity(@ptrCast(item_refs)); | ||
| 11361 | cases_extra.appendSliceAssumeCapacity(@ptrCast(range_refs)); | ||
| 11362 | cases_extra.appendSliceAssumeCapacity(@ptrCast(case_block.instructions.items)); | ||
| 11363 | } | 11324 | } |
| 11325 | |||
| 11326 | cases_len += 1; | ||
| 11327 | case_block.instructions.clearRetainingCapacity(); | ||
| 11328 | case_block.error_return_trace_index = child_block.error_return_trace_index; | ||
| 11329 | |||
| 11330 | const prong_hint: std.builtin.BranchHint = hint: { | ||
| 11331 | if (any_analyze_body) break :hint try sema.analyzeSwitchProng( | ||
| 11332 | &case_block, | ||
| 11333 | operand, | ||
| 11334 | operand_ty, | ||
| 11335 | raw_operand_ty, | ||
| 11336 | prong_body, | ||
| 11337 | block.src(.{ .switch_capture = .{ | ||
| 11338 | .switch_node_offset = src_node_offset, | ||
| 11339 | .case_idx = case.index, | ||
| 11340 | } }), | ||
| 11341 | prong_info.capture, | ||
| 11342 | prong_info.has_tag_capture, | ||
| 11343 | .none, | ||
| 11344 | .{ .item_refs = item_refs }, | ||
| 11345 | validated_switch.else_err_ty, | ||
| 11346 | switch_inst, | ||
| 11347 | zir_switch, | ||
| 11348 | ); | ||
| 11349 | _ = try case_block.addNoOp(.unreach); | ||
| 11350 | break :hint .cold; // unreachable branches are cold | ||
| 11351 | }; | ||
| 11352 | try branch_hints.append(gpa, prong_hint); | ||
| 11353 | |||
| 11354 | try cases_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr.Case).@"struct".fields.len + | ||
| 11355 | item_refs.len + | ||
| 11356 | 2 * range_refs.len + | ||
| 11357 | case_block.instructions.items.len); | ||
| 11358 | cases_extra.appendSliceAssumeCapacity(&payloadToExtraItems(Air.SwitchBr.Case{ | ||
| 11359 | .items_len = @intCast(item_refs.len), | ||
| 11360 | .ranges_len = @intCast(range_refs.len), | ||
| 11361 | .body_len = @intCast(case_block.instructions.items.len), | ||
| 11362 | })); | ||
| 11363 | cases_extra.appendSliceAssumeCapacity(@ptrCast(item_refs)); | ||
| 11364 | cases_extra.appendSliceAssumeCapacity(@ptrCast(range_refs)); | ||
| 11365 | cases_extra.appendSliceAssumeCapacity(@ptrCast(case_block.instructions.items)); | ||
| 11364 | } | 11366 | } |
| 11365 | 11367 | ||
| 11366 | const catch_all_extra: []const u32 = catch_all_extra: { | 11368 | const catch_all_extra: []const u32 = catch_all_extra: { |
| ... | @@ -11499,7 +11501,7 @@ fn finishSwitchBr( | ... | @@ -11499,7 +11501,7 @@ fn finishSwitchBr( |
| 11499 | try branch_hints.append(gpa, prong_hint); | 11501 | try branch_hints.append(gpa, prong_hint); |
| 11500 | 11502 | ||
| 11501 | try cases_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr.Case).@"struct".fields.len + | 11503 | try cases_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr.Case).@"struct".fields.len + |
| 11502 | (validated_switch.seen_enum_fields.len - zir_switch.totalItemsLen()) + | 11504 | (validated_switch.seen_enum_fields.len + 1 - zir_switch.totalItemsLen()) + // +1 because totalItemsLen includes the _ |
| 11503 | case_block.instructions.items.len); | 11505 | case_block.instructions.items.len); |
| 11504 | const extra_case = cases_extra.addManyAsArrayAssumeCapacity( | 11506 | const extra_case = cases_extra.addManyAsArrayAssumeCapacity( |
| 11505 | @typeInfo(Air.SwitchBr.Case).@"struct".fields.len, | 11507 | @typeInfo(Air.SwitchBr.Case).@"struct".fields.len, |
| ... | @@ -11555,7 +11557,7 @@ fn finishSwitchBr( | ... | @@ -11555,7 +11557,7 @@ fn finishSwitchBr( |
| 11555 | if (analyze_catch_all_body) { | 11557 | if (analyze_catch_all_body) { |
| 11556 | const index, const body, const capture, const has_tag_capture = switch (catch_all_case) { | 11558 | const index, const body, const capture, const has_tag_capture = switch (catch_all_case) { |
| 11557 | .@"else" => .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture }, | 11559 | .@"else" => .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture }, |
| 11558 | .under => .{ under_case.index, under_case.body, under_case.capture, under_case.has_tag_capture }, | 11560 | .under => .{ under_prong.?.index, under_prong.?.body, under_prong.?.capture, under_prong.?.has_tag_capture }, |
| 11559 | .none => unreachable, | 11561 | .none => unreachable, |
| 11560 | }; | 11562 | }; |
| 11561 | break :hint try sema.analyzeSwitchProng( | 11563 | break :hint try sema.analyzeSwitchProng( |
| ... | @@ -11734,7 +11736,6 @@ fn fixupSwitchContinues( | ... | @@ -11734,7 +11736,6 @@ fn fixupSwitchContinues( |
| 11734 | const ValidatedSwitchBlock = struct { | 11736 | const ValidatedSwitchBlock = struct { |
| 11735 | seen_enum_fields: []const ?LazySrcLoc, | 11737 | seen_enum_fields: []const ?LazySrcLoc, |
| 11736 | seen_errors: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, LazySrcLoc), | 11738 | seen_errors: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, LazySrcLoc), |
| 11737 | seen_sparse_values: std.AutoHashMapUnmanaged(InternPool.Index, LazySrcLoc), | ||
| 11738 | seen_ranges: []const RangeSet.Range, | 11739 | seen_ranges: []const RangeSet.Range, |
| 11739 | true_src: ?LazySrcLoc, | 11740 | true_src: ?LazySrcLoc, |
| 11740 | false_src: ?LazySrcLoc, | 11741 | false_src: ?LazySrcLoc, |
| ... | @@ -11742,7 +11743,6 @@ const ValidatedSwitchBlock = struct { | ... | @@ -11742,7 +11743,6 @@ const ValidatedSwitchBlock = struct { |
| 11742 | 11743 | ||
| 11743 | case_vals: []const Air.Inst.Ref, | 11744 | case_vals: []const Air.Inst.Ref, |
| 11744 | else_case: Zir.UnwrappedSwitchBlock.Case.Else, | 11745 | else_case: Zir.UnwrappedSwitchBlock.Case.Else, |
| 11745 | under_case: Zir.UnwrappedSwitchBlock.Case.Under.Resolved, | ||
| 11746 | else_err_ty: ?Type, | 11746 | else_err_ty: ?Type, |
| 11747 | 11747 | ||
| 11748 | fn iterateUnhandledItems( | 11748 | fn iterateUnhandledItems( |
| ... | @@ -11868,7 +11868,6 @@ fn validateSwitchBlock( | ... | @@ -11868,7 +11868,6 @@ fn validateSwitchBlock( |
| 11868 | const src = block.nodeOffset(src_node_offset); | 11868 | const src = block.nodeOffset(src_node_offset); |
| 11869 | const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset }); | 11869 | const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset }); |
| 11870 | const else_prong_src = block.src(.{ .node_offset_switch_else_prong = src_node_offset }); | 11870 | const else_prong_src = block.src(.{ .node_offset_switch_else_prong = src_node_offset }); |
| 11871 | const under_prong_src = block.src(.{ .node_offset_switch_under_prong = src_node_offset }); | ||
| 11872 | var extra_index = zir_switch.end; | 11871 | var extra_index = zir_switch.end; |
| 11873 | 11872 | ||
| 11874 | // We want to map values to our placeholders later on. | 11873 | // We want to map values to our placeholders later on. |
| ... | @@ -11948,33 +11947,7 @@ fn validateSwitchBlock( | ... | @@ -11948,33 +11947,7 @@ fn validateSwitchBlock( |
| 11948 | }; | 11947 | }; |
| 11949 | 11948 | ||
| 11950 | const has_else = zir_switch.else_case != null; | 11949 | const has_else = zir_switch.else_case != null; |
| 11951 | const has_under = zir_switch.under_case != .none; | 11950 | const has_under = zir_switch.has_under; |
| 11952 | |||
| 11953 | // Validate usage of '_' prongs. | ||
| 11954 | if (has_under and !operand_ty.isNonexhaustiveEnum(zcu)) { | ||
| 11955 | const msg = msg: { | ||
| 11956 | const msg = try sema.errMsg( | ||
| 11957 | src, | ||
| 11958 | "'_' prong only allowed when switching on non-exhaustive enums", | ||
| 11959 | .{}, | ||
| 11960 | ); | ||
| 11961 | errdefer msg.destroy(gpa); | ||
| 11962 | try sema.errNote( | ||
| 11963 | under_prong_src, | ||
| 11964 | msg, | ||
| 11965 | "'_' prong here", | ||
| 11966 | .{}, | ||
| 11967 | ); | ||
| 11968 | try sema.errNote( | ||
| 11969 | src, | ||
| 11970 | msg, | ||
| 11971 | "consider using 'else'", | ||
| 11972 | .{}, | ||
| 11973 | ); | ||
| 11974 | break :msg msg; | ||
| 11975 | }; | ||
| 11976 | return sema.failWithOwnedErrorMsg(block, msg); | ||
| 11977 | } | ||
| 11978 | 11951 | ||
| 11979 | var case_vals: std.ArrayList(Air.Inst.Ref) = .empty; | 11952 | var case_vals: std.ArrayList(Air.Inst.Ref) = .empty; |
| 11980 | try case_vals.ensureUnusedCapacity(arena, zir_switch.item_infos.len); | 11953 | try case_vals.ensureUnusedCapacity(arena, zir_switch.item_infos.len); |
| ... | @@ -11991,7 +11964,6 @@ fn validateSwitchBlock( | ... | @@ -11991,7 +11964,6 @@ fn validateSwitchBlock( |
| 11991 | var else_err_ty: ?Type = null; | 11964 | var else_err_ty: ?Type = null; |
| 11992 | 11965 | ||
| 11993 | const else_case = zir_switch.else_case orelse undefined; | 11966 | const else_case = zir_switch.else_case orelse undefined; |
| 11994 | var under_case = zir_switch.under_case.resolve() orelse undefined; | ||
| 11995 | 11967 | ||
| 11996 | switch (item_ty.zigTypeTag(zcu)) { | 11968 | switch (item_ty.zigTypeTag(zcu)) { |
| 11997 | .@"union" => unreachable, | 11969 | .@"union" => unreachable, |
| ... | @@ -12020,16 +11992,6 @@ fn validateSwitchBlock( | ... | @@ -12020,16 +11992,6 @@ fn validateSwitchBlock( |
| 12020 | var case_it = zir_switch.iterateCases(); | 11992 | var case_it = zir_switch.iterateCases(); |
| 12021 | while (case_it.next()) |case| { | 11993 | while (case_it.next()) |case| { |
| 12022 | const prong_info = case.prong_info; | 11994 | const prong_info = case.prong_info; |
| 12023 | const is_under = case.isUnder(); | ||
| 12024 | if (is_under) { | ||
| 12025 | assert(!prong_info.is_inline); | ||
| 12026 | under_case = .{ | ||
| 12027 | .index = case.index, | ||
| 12028 | .body = sema.code.bodySlice(extra_index, prong_info.body_len), | ||
| 12029 | .capture = prong_info.capture, | ||
| 12030 | .has_tag_capture = prong_info.has_tag_capture, | ||
| 12031 | }; | ||
| 12032 | } | ||
| 12033 | extra_index += prong_info.body_len; | 11995 | extra_index += prong_info.body_len; |
| 12034 | for (case.item_infos, 0..) |item_info, item_i| { | 11996 | for (case.item_infos, 0..) |item_info, item_i| { |
| 12035 | const item_src = block.src(.{ .switch_case_item = .{ | 11997 | const item_src = block.src(.{ .switch_case_item = .{ |
| ... | @@ -12037,9 +11999,34 @@ fn validateSwitchBlock( | ... | @@ -12037,9 +11999,34 @@ fn validateSwitchBlock( |
| 12037 | .case_idx = case.index, | 11999 | .case_idx = case.index, |
| 12038 | .item_idx = .{ .kind = .single, .value = @intCast(item_i) }, | 12000 | .item_idx = .{ .kind = .single, .value = @intCast(item_i) }, |
| 12039 | } }); | 12001 | } }); |
| 12040 | const item, extra_index = try sema.resolveSwitchItem(block, item_src, item_ty, item_info, extra_index, switch_inst, prong_info.is_comptime_unreach, prong_info.is_inline); | 12002 | if (item_info.unwrap() == .under) { |
| 12041 | try sema.validateSwitchItemOrRange(block, item_src, item.val, null, item_ty, seen_enum_fields, &seen_errors, &seen_sparse_values, &range_set, &true_src, &false_src, &void_src); | 12003 | if (!operand_ty.isNonexhaustiveEnum(zcu)) return sema.failWithOwnedErrorMsg(block, msg: { |
| 12042 | if (!is_under) case_vals.appendAssumeCapacity(item.ref); | 12004 | const msg = try sema.errMsg( |
| 12005 | src, | ||
| 12006 | "'_' prong only allowed when switching on non-exhaustive enums", | ||
| 12007 | .{}, | ||
| 12008 | ); | ||
| 12009 | errdefer msg.destroy(gpa); | ||
| 12010 | try sema.errNote( | ||
| 12011 | item_src, | ||
| 12012 | msg, | ||
| 12013 | "'_' prong here", | ||
| 12014 | .{}, | ||
| 12015 | ); | ||
| 12016 | try sema.errNote( | ||
| 12017 | src, | ||
| 12018 | msg, | ||
| 12019 | "consider using 'else'", | ||
| 12020 | .{}, | ||
| 12021 | ); | ||
| 12022 | break :msg msg; | ||
| 12023 | }); | ||
| 12024 | case_vals.appendAssumeCapacity(.none); | ||
| 12025 | } else { | ||
| 12026 | const item, extra_index = try sema.resolveSwitchItem(block, item_src, item_ty, item_info, extra_index, switch_inst, prong_info.is_comptime_unreach); | ||
| 12027 | try sema.validateSwitchItemOrRange(block, item_src, item.val, null, item_ty, seen_enum_fields, &seen_errors, &seen_sparse_values, &range_set, &true_src, &false_src, &void_src); | ||
| 12028 | case_vals.appendAssumeCapacity(item.ref); | ||
| 12029 | } | ||
| 12043 | } | 12030 | } |
| 12044 | for (case.range_infos, 0..) |range_info, range_i| { | 12031 | for (case.range_infos, 0..) |range_info, range_i| { |
| 12045 | const range_offset: LazySrcLoc.Offset.SwitchItem = .{ | 12032 | const range_offset: LazySrcLoc.Offset.SwitchItem = .{ |
| ... | @@ -12050,10 +12037,10 @@ fn validateSwitchBlock( | ... | @@ -12050,10 +12037,10 @@ fn validateSwitchBlock( |
| 12050 | const range_src = block.src(.{ .switch_case_item = range_offset }); | 12037 | const range_src = block.src(.{ .switch_case_item = range_offset }); |
| 12051 | const first_src = block.src(.{ .switch_case_item_range_first = range_offset }); | 12038 | const first_src = block.src(.{ .switch_case_item_range_first = range_offset }); |
| 12052 | const last_src = block.src(.{ .switch_case_item_range_last = range_offset }); | 12039 | const last_src = block.src(.{ .switch_case_item_range_last = range_offset }); |
| 12053 | const first_item, extra_index = try sema.resolveSwitchItem(block, first_src, item_ty, range_info[0], extra_index, switch_inst, prong_info.is_comptime_unreach, prong_info.is_inline); | 12040 | const first_item, extra_index = try sema.resolveSwitchItem(block, first_src, item_ty, range_info[0], extra_index, switch_inst, prong_info.is_comptime_unreach); |
| 12054 | const last_item, extra_index = try sema.resolveSwitchItem(block, last_src, item_ty, range_info[1], extra_index, switch_inst, prong_info.is_comptime_unreach, prong_info.is_inline); | 12041 | const last_item, extra_index = try sema.resolveSwitchItem(block, last_src, item_ty, range_info[1], extra_index, switch_inst, prong_info.is_comptime_unreach); |
| 12055 | try sema.validateSwitchItemOrRange(block, range_src, first_item.val, last_item.val, item_ty, seen_enum_fields, &seen_errors, &seen_sparse_values, &range_set, &true_src, &false_src, &void_src); | 12042 | try sema.validateSwitchItemOrRange(block, range_src, first_item.val, last_item.val, item_ty, seen_enum_fields, &seen_errors, &seen_sparse_values, &range_set, &true_src, &false_src, &void_src); |
| 12056 | if (!is_under) case_vals.appendSliceAssumeCapacity(&.{ first_item.ref, last_item.ref }); | 12043 | case_vals.appendSliceAssumeCapacity(&.{ first_item.ref, last_item.ref }); |
| 12057 | } | 12044 | } |
| 12058 | } | 12045 | } |
| 12059 | 12046 | ||
| ... | @@ -12285,7 +12272,6 @@ fn validateSwitchBlock( | ... | @@ -12285,7 +12272,6 @@ fn validateSwitchBlock( |
| 12285 | return .{ | 12272 | return .{ |
| 12286 | .seen_enum_fields = seen_enum_fields, | 12273 | .seen_enum_fields = seen_enum_fields, |
| 12287 | .seen_errors = seen_errors, | 12274 | .seen_errors = seen_errors, |
| 12288 | .seen_sparse_values = seen_sparse_values, | ||
| 12289 | .seen_ranges = range_set.ranges.items, | 12275 | .seen_ranges = range_set.ranges.items, |
| 12290 | .true_src = true_src, | 12276 | .true_src = true_src, |
| 12291 | .false_src = false_src, | 12277 | .false_src = false_src, |
| ... | @@ -12293,7 +12279,6 @@ fn validateSwitchBlock( | ... | @@ -12293,7 +12279,6 @@ fn validateSwitchBlock( |
| 12293 | 12279 | ||
| 12294 | .case_vals = case_vals.items, | 12280 | .case_vals = case_vals.items, |
| 12295 | .else_case = else_case, | 12281 | .else_case = else_case, |
| 12296 | .under_case = under_case, | ||
| 12297 | .else_err_ty = else_err_ty, | 12282 | .else_err_ty = else_err_ty, |
| 12298 | }; | 12283 | }; |
| 12299 | } | 12284 | } |
| ... | @@ -12334,19 +12319,13 @@ fn resolveSwitchBlock( | ... | @@ -12334,19 +12319,13 @@ fn resolveSwitchBlock( |
| 12334 | var case_val_idx: usize = 0; | 12319 | var case_val_idx: usize = 0; |
| 12335 | var extra_index = zir_switch.end; | 12320 | var extra_index = zir_switch.end; |
| 12336 | var case_it = zir_switch.iterateCases(); | 12321 | var case_it = zir_switch.iterateCases(); |
| 12322 | var under_prong: ?struct { | ||
| 12323 | index: Zir.UnwrappedSwitchBlock.Case.Index, | ||
| 12324 | body: []const Zir.Inst.Index, | ||
| 12325 | capture: Zir.Inst.SwitchBlock.ProngInfo.Capture, | ||
| 12326 | has_tag_capture: bool, | ||
| 12327 | } = null; | ||
| 12337 | while (case_it.next()) |case| { | 12328 | while (case_it.next()) |case| { |
| 12338 | if (case.isUnder()) { // we'll deal with this later | ||
| 12339 | extra_index += case.prong_info.body_len; | ||
| 12340 | for (case.item_infos) |item_info| { | ||
| 12341 | if (item_info.bodyLen()) |body_len| extra_index += body_len; | ||
| 12342 | } | ||
| 12343 | for (case.range_infos) |range_info| { | ||
| 12344 | if (range_info[0].bodyLen()) |body_len| extra_index += body_len; | ||
| 12345 | if (range_info[1].bodyLen()) |body_len| extra_index += body_len; | ||
| 12346 | } | ||
| 12347 | continue; | ||
| 12348 | } | ||
| 12349 | |||
| 12350 | const prong_info = case.prong_info; | 12329 | const prong_info = case.prong_info; |
| 12351 | const prong_body = sema.code.bodySlice(extra_index, prong_info.body_len); | 12330 | const prong_body = sema.code.bodySlice(extra_index, prong_info.body_len); |
| 12352 | extra_index += prong_body.len; | 12331 | extra_index += prong_body.len; |
| ... | @@ -12363,6 +12342,15 @@ fn resolveSwitchBlock( | ... | @@ -12363,6 +12342,15 @@ fn resolveSwitchBlock( |
| 12363 | const range_refs: []const [2]Air.Inst.Ref = @ptrCast(case_vals[case_val_idx..][0 .. 2 * case.range_infos.len]); | 12342 | const range_refs: []const [2]Air.Inst.Ref = @ptrCast(case_vals[case_val_idx..][0 .. 2 * case.range_infos.len]); |
| 12364 | case_val_idx += 2 * range_refs.len; | 12343 | case_val_idx += 2 * range_refs.len; |
| 12365 | for (item_refs) |item_ref| { | 12344 | for (item_refs) |item_ref| { |
| 12345 | if (item_ref == .none) { | ||
| 12346 | under_prong = .{ | ||
| 12347 | .index = case.index, | ||
| 12348 | .body = prong_body, | ||
| 12349 | .capture = case.prong_info.capture, | ||
| 12350 | .has_tag_capture = case.prong_info.has_tag_capture, | ||
| 12351 | }; | ||
| 12352 | continue; | ||
| 12353 | } | ||
| 12366 | const item_val = sema.resolveConstDefinedValue(child_block, .unneeded, item_ref, undefined) catch unreachable; | 12354 | const item_val = sema.resolveConstDefinedValue(child_block, .unneeded, item_ref, undefined) catch unreachable; |
| 12367 | if (cond_val.eql(item_val, item_ty, zcu)) { | 12355 | if (cond_val.eql(item_val, item_ty, zcu)) { |
| 12368 | if (err_set) try sema.maybeErrorUnwrapComptime(child_block, prong_body, cond_ref); | 12356 | if (err_set) try sema.maybeErrorUnwrapComptime(child_block, prong_body, cond_ref); |
| ... | @@ -12421,7 +12409,6 @@ fn resolveSwitchBlock( | ... | @@ -12421,7 +12409,6 @@ fn resolveSwitchBlock( |
| 12421 | } | 12409 | } |
| 12422 | 12410 | ||
| 12423 | const else_case = validated_switch.else_case; | 12411 | const else_case = validated_switch.else_case; |
| 12424 | const under_case = validated_switch.under_case; | ||
| 12425 | 12412 | ||
| 12426 | // named-only prong | 12413 | // named-only prong |
| 12427 | 12414 | ||
| ... | @@ -12452,7 +12439,7 @@ fn resolveSwitchBlock( | ... | @@ -12452,7 +12439,7 @@ fn resolveSwitchBlock( |
| 12452 | 12439 | ||
| 12453 | const index, const body, const capture, const has_tag_capture, const is_inline = switch (catch_all_case) { | 12440 | const index, const body, const capture, const has_tag_capture, const is_inline = switch (catch_all_case) { |
| 12454 | .@"else" => .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture, else_case.is_inline }, | 12441 | .@"else" => .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture, else_case.is_inline }, |
| 12455 | .under => .{ under_case.index, under_case.body, under_case.capture, under_case.has_tag_capture, false }, | 12442 | .under => .{ under_prong.?.index, under_prong.?.body, under_prong.?.capture, under_prong.?.has_tag_capture, false }, |
| 12456 | .none => unreachable, | 12443 | .none => unreachable, |
| 12457 | }; | 12444 | }; |
| 12458 | if (err_set) try sema.maybeErrorUnwrapComptime(child_block, body, cond_ref); | 12445 | if (err_set) try sema.maybeErrorUnwrapComptime(child_block, body, cond_ref); |
| ... | @@ -13169,7 +13156,6 @@ fn resolveSwitchItem( | ... | @@ -13169,7 +13156,6 @@ fn resolveSwitchItem( |
| 13169 | extra_index: usize, | 13156 | extra_index: usize, |
| 13170 | switch_inst: Zir.Inst.Index, | 13157 | switch_inst: Zir.Inst.Index, |
| 13171 | prong_is_comptime_unreach: bool, | 13158 | prong_is_comptime_unreach: bool, |
| 13172 | prong_is_inline: bool, | ||
| 13173 | ) CompileError!ResolvedSwitchItemAndExtraIndex { | 13159 | ) CompileError!ResolvedSwitchItemAndExtraIndex { |
| 13174 | const pt = sema.pt; | 13160 | const pt = sema.pt; |
| 13175 | const zcu = pt.zcu; | 13161 | const zcu = pt.zcu; |
| ... | @@ -13180,6 +13166,7 @@ fn resolveSwitchItem( | ... | @@ -13180,6 +13166,7 @@ fn resolveSwitchItem( |
| 13180 | 13166 | ||
| 13181 | var end = extra_index; | 13167 | var end = extra_index; |
| 13182 | const uncoerced: Air.Inst.Ref, const uncoerced_ty: Type = uncoerced: switch (item_info.unwrap()) { | 13168 | const uncoerced: Air.Inst.Ref, const uncoerced_ty: Type = uncoerced: switch (item_info.unwrap()) { |
| 13169 | .under => unreachable, // caller must check this before calling us | ||
| 13183 | .enum_literal => |str_index| { | 13170 | .enum_literal => |str_index| { |
| 13184 | const zir_str = sema.code.nullTerminatedString(str_index); | 13171 | const zir_str = sema.code.nullTerminatedString(str_index); |
| 13185 | const name = try ip.getOrPutString(gpa, io, pt.tid, zir_str, .no_embedded_nulls); | 13172 | const name = try ip.getOrPutString(gpa, io, pt.tid, zir_str, .no_embedded_nulls); |
| ... | @@ -13198,10 +13185,6 @@ fn resolveSwitchItem( | ... | @@ -13198,10 +13185,6 @@ fn resolveSwitchItem( |
| 13198 | } })); | 13185 | } })); |
| 13199 | break :uncoerced .{ uncoerced, err_set_ty }; | 13186 | break :uncoerced .{ uncoerced, err_set_ty }; |
| 13200 | }, | 13187 | }, |
| 13201 | .number_literal => |zir_ref| { | ||
| 13202 | const uncoerced = try sema.resolveInst(zir_ref); | ||
| 13203 | break :uncoerced .{ uncoerced, sema.typeOf(uncoerced) }; | ||
| 13204 | }, | ||
| 13205 | .body_len => |body_len| { | 13188 | .body_len => |body_len| { |
| 13206 | const body = sema.code.bodySlice(extra_index, body_len); | 13189 | const body = sema.code.bodySlice(extra_index, body_len); |
| 13207 | end += body.len; | 13190 | end += body.len; |
| ... | @@ -13231,7 +13214,7 @@ fn resolveSwitchItem( | ... | @@ -13231,7 +13214,7 @@ fn resolveSwitchItem( |
| 13231 | .ok => if (try sema.resolveValue(uncoerced)) |uncoerced_val| { | 13214 | .ok => if (try sema.resolveValue(uncoerced)) |uncoerced_val| { |
| 13232 | break :item_ref try sema.coerceInMemory(uncoerced_val, item_ty); | 13215 | break :item_ref try sema.coerceInMemory(uncoerced_val, item_ty); |
| 13233 | }, | 13216 | }, |
| 13234 | .missing_error => if (prong_is_comptime_unreach and !prong_is_inline) { | 13217 | .missing_error => if (prong_is_comptime_unreach) { |
| 13235 | break :item_ref uncoerced; | 13218 | break :item_ref uncoerced; |
| 13236 | }, | 13219 | }, |
| 13237 | .from_anyerror => {}, | 13220 | .from_anyerror => {}, |
src/Zcu.zig+1-41| ... | @@ -1742,27 +1742,6 @@ pub const SrcLoc = struct { | ... | @@ -1742,27 +1742,6 @@ pub const SrcLoc = struct { |
| 1742 | } else unreachable; | 1742 | } else unreachable; |
| 1743 | }, | 1743 | }, |
| 1744 | 1744 | ||
| 1745 | .node_offset_switch_under_prong => |node_off| { | ||
| 1746 | const tree = try src_loc.file_scope.getTree(zcu); | ||
| 1747 | const switch_node = node_off.toAbsolute(src_loc.base_node); | ||
| 1748 | _, const extra_index = tree.nodeData(switch_node).node_and_extra; | ||
| 1749 | const case_nodes = tree.extraDataSlice(tree.extraData(extra_index, Ast.Node.SubRange), Ast.Node.Index); | ||
| 1750 | for (case_nodes) |case_node| { | ||
| 1751 | const case = tree.fullSwitchCase(case_node).?; | ||
| 1752 | for (case.ast.values) |val| { | ||
| 1753 | if (tree.nodeTag(val) == .identifier and | ||
| 1754 | mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(val)), "_")) | ||
| 1755 | { | ||
| 1756 | return tree.tokensToSpan( | ||
| 1757 | tree.firstToken(case_node), | ||
| 1758 | tree.lastToken(case_node), | ||
| 1759 | tree.nodeMainToken(val), | ||
| 1760 | ); | ||
| 1761 | } | ||
| 1762 | } | ||
| 1763 | } else unreachable; | ||
| 1764 | }, | ||
| 1765 | |||
| 1766 | .node_offset_switch_range => |node_off| { | 1745 | .node_offset_switch_range => |node_off| { |
| 1767 | const tree = try src_loc.file_scope.getTree(zcu); | 1746 | const tree = try src_loc.file_scope.getTree(zcu); |
| 1768 | const switch_node = node_off.toAbsolute(src_loc.base_node); | 1747 | const switch_node = node_off.toAbsolute(src_loc.base_node); |
| ... | @@ -2176,7 +2155,6 @@ pub const SrcLoc = struct { | ... | @@ -2176,7 +2155,6 @@ pub const SrcLoc = struct { |
| 2176 | 2155 | ||
| 2177 | var multi_i: u32 = 0; | 2156 | var multi_i: u32 = 0; |
| 2178 | var scalar_i: u32 = 0; | 2157 | var scalar_i: u32 = 0; |
| 2179 | var underscore_node: Ast.Node.OptionalIndex = .none; | ||
| 2180 | const case: Ast.full.SwitchCase = case: for (case_nodes) |case_node| { | 2158 | const case: Ast.full.SwitchCase = case: for (case_nodes) |case_node| { |
| 2181 | const case = tree.fullSwitchCase(case_node).?; | 2159 | const case = tree.fullSwitchCase(case_node).?; |
| 2182 | if (case.ast.values.len == 0) { | 2160 | if (case.ast.values.len == 0) { |
| ... | @@ -2185,17 +2163,6 @@ pub const SrcLoc = struct { | ... | @@ -2185,17 +2163,6 @@ pub const SrcLoc = struct { |
| 2185 | } | 2163 | } |
| 2186 | continue :case; | 2164 | continue :case; |
| 2187 | } | 2165 | } |
| 2188 | if (underscore_node == .none) { | ||
| 2189 | for (case.ast.values) |value| { | ||
| 2190 | if (tree.nodeTag(value) == .identifier and | ||
| 2191 | mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(value)), "_")) | ||
| 2192 | { | ||
| 2193 | underscore_node = value.toOptional(); | ||
| 2194 | if (want_case_idx.is_under) break :case case; | ||
| 2195 | if (case.ast.values.len == 1) continue :case; | ||
| 2196 | } | ||
| 2197 | } | ||
| 2198 | } | ||
| 2199 | 2166 | ||
| 2200 | const is_multi = case.ast.values.len != 1 or | 2167 | const is_multi = case.ast.values.len != 1 or |
| 2201 | tree.nodeTag(case.ast.values[0]) == .switch_range; | 2168 | tree.nodeTag(case.ast.values[0]) == .switch_range; |
| ... | @@ -2220,7 +2187,6 @@ pub const SrcLoc = struct { | ... | @@ -2220,7 +2187,6 @@ pub const SrcLoc = struct { |
| 2220 | .switch_case_item_range_last, | 2187 | .switch_case_item_range_last, |
| 2221 | => |x| item_idx: { | 2188 | => |x| item_idx: { |
| 2222 | assert(want_case_idx != Zir.UnwrappedSwitchBlock.Case.Index.@"else"); | 2189 | assert(want_case_idx != Zir.UnwrappedSwitchBlock.Case.Index.@"else"); |
| 2223 | assert(want_case_idx != Zir.UnwrappedSwitchBlock.Case.Index.bare_under); | ||
| 2224 | break :item_idx x.item_idx; | 2190 | break :item_idx x.item_idx; |
| 2225 | }, | 2191 | }, |
| 2226 | .switch_capture, .switch_tag_capture => { | 2192 | .switch_capture, .switch_tag_capture => { |
| ... | @@ -2247,9 +2213,7 @@ pub const SrcLoc = struct { | ... | @@ -2247,9 +2213,7 @@ pub const SrcLoc = struct { |
| 2247 | .single => { | 2213 | .single => { |
| 2248 | var item_i: u32 = 0; | 2214 | var item_i: u32 = 0; |
| 2249 | for (case.ast.values) |item_node| { | 2215 | for (case.ast.values) |item_node| { |
| 2250 | if (item_node.toOptional() == underscore_node or | 2216 | if (tree.nodeTag(item_node) == .switch_range) { |
| 2251 | tree.nodeTag(item_node) == .switch_range) | ||
| 2252 | { | ||
| 2253 | continue; | 2217 | continue; |
| 2254 | } | 2218 | } |
| 2255 | if (item_i != want_item_idx.value) { | 2219 | if (item_i != want_item_idx.value) { |
| ... | @@ -2456,10 +2420,6 @@ pub const LazySrcLoc = struct { | ... | @@ -2456,10 +2420,6 @@ pub const LazySrcLoc = struct { |
| 2456 | /// by taking this AST node index offset from the containing base node, | 2420 | /// by taking this AST node index offset from the containing base node, |
| 2457 | /// which points to a switch expression AST node. Next, navigate to the else prong. | 2421 | /// which points to a switch expression AST node. Next, navigate to the else prong. |
| 2458 | node_offset_switch_else_prong: Ast.Node.Offset, | 2422 | node_offset_switch_else_prong: Ast.Node.Offset, |
| 2459 | /// The source location points to the `_` prong of a switch expression, found | ||
| 2460 | /// by taking this AST node index offset from the containing base node, | ||
| 2461 | /// which points to a switch expression AST node. Next, navigate to the `_` prong. | ||
| 2462 | node_offset_switch_under_prong: Ast.Node.Offset, | ||
| 2463 | /// The source location points to all the ranges of a switch expression, found | 2423 | /// The source location points to all the ranges of a switch expression, found |
| 2464 | /// by taking this AST node index offset from the containing base node, | 2424 | /// by taking this AST node index offset from the containing base node, |
| 2465 | /// which points to a switch expression AST node. Next, navigate to any of the | 2425 | /// which points to a switch expression AST node. Next, navigate to any of the |
src/print_zir.zig+37-47| ... | @@ -2021,15 +2021,6 @@ const Writer = struct { | ... | @@ -2021,15 +2021,6 @@ const Writer = struct { |
| 2021 | try stream.writeAll("else => "); | 2021 | try stream.writeAll("else => "); |
| 2022 | try self.writeBracedBody(stream, else_case.body); | 2022 | try self.writeBracedBody(stream, else_case.body); |
| 2023 | } | 2023 | } |
| 2024 | if (zir_switch.under_case.resolve()) |under_case| { | ||
| 2025 | try stream.writeAll(",\n"); | ||
| 2026 | try stream.splatByteAll(' ', self.indent); | ||
| 2027 | |||
| 2028 | try self.writeSwitchCaptures(stream, under_case.capture, under_case.has_tag_capture, inst, &zir_switch); | ||
| 2029 | |||
| 2030 | try stream.writeAll("_ => "); | ||
| 2031 | try self.writeBracedBody(stream, under_case.body); | ||
| 2032 | } | ||
| 2033 | 2024 | ||
| 2034 | var case_it = zir_switch.iterateCases(); | 2025 | var case_it = zir_switch.iterateCases(); |
| 2035 | while (case_it.next()) |case| { | 2026 | while (case_it.next()) |case| { |
| ... | @@ -2043,14 +2034,8 @@ const Writer = struct { | ... | @@ -2043,14 +2034,8 @@ const Writer = struct { |
| 2043 | const prong_body = self.code.bodySlice(extra_index, prong_info.body_len); | 2034 | const prong_body = self.code.bodySlice(extra_index, prong_info.body_len); |
| 2044 | extra_index += prong_body.len; | 2035 | extra_index += prong_body.len; |
| 2045 | 2036 | ||
| 2046 | var first_item: bool = true; | 2037 | for (case.item_infos, 0..) |item_info, i| { |
| 2047 | if (case.isUnder()) { | 2038 | if (i > 0) try stream.writeAll(", "); |
| 2048 | try stream.writeAll("_"); | ||
| 2049 | first_item = false; | ||
| 2050 | } | ||
| 2051 | for (case.item_infos) |item_info| { | ||
| 2052 | if (!first_item) try stream.writeAll(", "); | ||
| 2053 | first_item = false; | ||
| 2054 | 2039 | ||
| 2055 | switch (item_info.unwrap()) { | 2040 | switch (item_info.unwrap()) { |
| 2056 | .enum_literal => |str_index| { | 2041 | .enum_literal => |str_index| { |
| ... | @@ -2061,9 +2046,7 @@ const Writer = struct { | ... | @@ -2061,9 +2046,7 @@ const Writer = struct { |
| 2061 | const str = self.code.nullTerminatedString(str_index); | 2046 | const str = self.code.nullTerminatedString(str_index); |
| 2062 | try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)}); | 2047 | try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)}); |
| 2063 | }, | 2048 | }, |
| 2064 | .number_literal => |zir_ref| { | 2049 | .under => try stream.writeByte('_'), |
| 2065 | try self.writeInstRef(stream, zir_ref); | ||
| 2066 | }, | ||
| 2067 | .body_len => |body_len| { | 2050 | .body_len => |body_len| { |
| 2068 | const item_body = self.code.bodySlice(extra_index, body_len); | 2051 | const item_body = self.code.bodySlice(extra_index, body_len); |
| 2069 | extra_index += item_body.len; | 2052 | extra_index += item_body.len; |
| ... | @@ -2071,33 +2054,40 @@ const Writer = struct { | ... | @@ -2071,33 +2054,40 @@ const Writer = struct { |
| 2071 | }, | 2054 | }, |
| 2072 | } | 2055 | } |
| 2073 | } | 2056 | } |
| 2074 | for (case.range_infos) |range_info| { | 2057 | for (case.range_infos, 0..) |range_info, i| { |
| 2075 | if (!first_item) try stream.writeAll(", "); | 2058 | if (i > 0 and case.item_infos.len == 0) try stream.writeAll(", "); |
| 2076 | first_item = false; | 2059 | switch (range_info[0].unwrap()) { |
| 2077 | 2060 | .enum_literal => |str_index| { | |
| 2078 | var first_range_item = true; | 2061 | const str = self.code.nullTerminatedString(str_index); |
| 2079 | for (&range_info) |item_info| { | 2062 | try stream.print("\".{f}\"", .{std.zig.fmtString(str)}); |
| 2080 | if (!first_range_item) try stream.writeAll("..."); | 2063 | }, |
| 2081 | first_range_item = false; | 2064 | .error_value => |str_index| { |
| 2082 | 2065 | const str = self.code.nullTerminatedString(str_index); | |
| 2083 | switch (item_info.unwrap()) { | 2066 | try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)}); |
| 2084 | .enum_literal => |str_index| { | 2067 | }, |
| 2085 | const str = self.code.nullTerminatedString(str_index); | 2068 | .under => unreachable, // '_..._' is not allowed |
| 2086 | try stream.print("\".{f}\"", .{std.zig.fmtString(str)}); | 2069 | .body_len => |body_len| { |
| 2087 | }, | 2070 | const item_body = self.code.bodySlice(extra_index, body_len); |
| 2088 | .error_value => |str_index| { | 2071 | extra_index += item_body.len; |
| 2089 | const str = self.code.nullTerminatedString(str_index); | 2072 | try self.writeBracedDecl(stream, item_body); |
| 2090 | try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)}); | 2073 | }, |
| 2091 | }, | 2074 | } |
| 2092 | .number_literal => |zir_ref| { | 2075 | try stream.writeAll("..."); |
| 2093 | try self.writeInstRef(stream, zir_ref); | 2076 | switch (range_info[1].unwrap()) { |
| 2094 | }, | 2077 | .enum_literal => |str_index| { |
| 2095 | .body_len => |body_len| { | 2078 | const str = self.code.nullTerminatedString(str_index); |
| 2096 | const item_body = self.code.bodySlice(extra_index, body_len); | 2079 | try stream.print("\".{f}\"", .{std.zig.fmtString(str)}); |
| 2097 | extra_index += item_body.len; | 2080 | }, |
| 2098 | try self.writeBracedDecl(stream, item_body); | 2081 | .error_value => |str_index| { |
| 2099 | }, | 2082 | const str = self.code.nullTerminatedString(str_index); |
| 2100 | } | 2083 | try stream.print("\"error.{f}\"", .{std.zig.fmtString(str)}); |
| 2084 | }, | ||
| 2085 | .under => unreachable, // '_..._' is not allowed | ||
| 2086 | .body_len => |body_len| { | ||
| 2087 | const item_body = self.code.bodySlice(extra_index, body_len); | ||
| 2088 | extra_index += item_body.len; | ||
| 2089 | try self.writeBracedDecl(stream, item_body); | ||
| 2090 | }, | ||
| 2101 | } | 2091 | } |
| 2102 | } | 2092 | } |
| 2103 | try stream.writeAll(" => "); | 2093 | try stream.writeAll(" => "); |