authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-05-28 04:31:56+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-06-13 12:55:27+01:00
log42dc7539c5b0a39e9b64c5ad92757945b0ca05ad
tree6cdf873c6800aebccdd8c03a443f9594acb84729
parentbcb673d94ac09ec381e5b1ad1edf64b603ac68f1
signaturelock-open Commit is signed but in an unrecognized format.

Fix bad source locations in switch capture errors

To do this, I expanded SwitchProngSrc a bit. Several of the tags there aren't actually used by any current errors, but they're there for consistency and if we ever need them. Also delete a now-redundant test and fix another.

4 files changed, 122 insertions(+), 81 deletions(-)

src/Module.zig+101-45
......@@ -2471,12 +2471,23 @@ pub const SrcLoc = struct {
24712471 }
24722472 } else unreachable;
24732473 },
2474 .node_offset_switch_prong_capture => |node_off| {
2474 .node_offset_switch_prong_capture,
2475 .node_offset_switch_prong_tag_capture,
2476 => |node_off| {
24752477 const tree = try src_loc.file_scope.getTree(gpa);
24762478 const case_node = src_loc.declRelativeToNodeIndex(node_off);
24772479 const case = tree.fullSwitchCase(case_node).?;
2478 const start_tok = case.payload_token.?;
24792480 const token_tags = tree.tokens.items(.tag);
2481 const start_tok = switch (src_loc.lazy) {
2482 .node_offset_switch_prong_capture => case.payload_token.?,
2483 .node_offset_switch_prong_tag_capture => blk: {
2484 var tok = case.payload_token.?;
2485 if (token_tags[tok] == .asterisk) tok += 1;
2486 tok += 2; // skip over comma
2487 break :blk tok;
2488 },
2489 else => unreachable,
2490 };
24802491 const end_tok = switch (token_tags[start_tok]) {
24812492 .asterisk => start_tok + 1,
24822493 else => start_tok,
......@@ -2957,6 +2968,9 @@ pub const LazySrcLoc = union(enum) {
29572968 /// The source location points to the capture of a switch_prong.
29582969 /// The Decl is determined contextually.
29592970 node_offset_switch_prong_capture: i32,
2971 /// The source location points to the tag capture of a switch_prong.
2972 /// The Decl is determined contextually.
2973 node_offset_switch_prong_tag_capture: i32,
29602974 /// The source location points to the align expr of a function type
29612975 /// expression, found by taking this AST node index offset from the containing
29622976 /// Decl AST node, which points to a function type AST node. Next, navigate to
......@@ -3130,6 +3144,7 @@ pub const LazySrcLoc = union(enum) {
31303144 .node_offset_switch_special_prong,
31313145 .node_offset_switch_range,
31323146 .node_offset_switch_prong_capture,
3147 .node_offset_switch_prong_tag_capture,
31333148 .node_offset_fn_type_align,
31343149 .node_offset_fn_type_addrspace,
31353150 .node_offset_fn_type_section,
......@@ -5867,11 +5882,26 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void {
58675882}
58685883
58695884pub const SwitchProngSrc = union(enum) {
5885 /// The item for a scalar prong.
58705886 scalar: u32,
5887 /// A given single item for a multi prong.
58715888 multi: Multi,
5889 /// A given range item for a multi prong.
58725890 range: Multi,
5873 multi_capture: u32,
5891 /// The item for the special prong.
58745892 special,
5893 /// The main capture for a scalar prong.
5894 scalar_capture: u32,
5895 /// The main capture for a multi prong.
5896 multi_capture: u32,
5897 /// The main capture for the special prong.
5898 special_capture,
5899 /// The tag capture for a scalar prong.
5900 scalar_tag_capture: u32,
5901 /// The tag capture for a multi prong.
5902 multi_tag_capture: u32,
5903 /// The tag capture for the special prong.
5904 special_tag_capture,
58755905
58765906 pub const Multi = struct {
58775907 prong: u32,
......@@ -5887,6 +5917,7 @@ pub const SwitchProngSrc = union(enum) {
58875917 mod: *Module,
58885918 decl: *Decl,
58895919 switch_node_offset: i32,
5920 /// Ignored if `prong_src` is not `.range`
58905921 range_expand: RangeExpand,
58915922 ) LazySrcLoc {
58925923 @setCold(true);
......@@ -5907,7 +5938,7 @@ pub const SwitchProngSrc = union(enum) {
59075938
59085939 var multi_i: u32 = 0;
59095940 var scalar_i: u32 = 0;
5910 for (case_nodes) |case_node| {
5941 const case_node = for (case_nodes) |case_node| {
59115942 const case = tree.fullSwitchCase(case_node).?;
59125943
59135944 const is_special = special: {
......@@ -5919,60 +5950,85 @@ pub const SwitchProngSrc = union(enum) {
59195950 };
59205951
59215952 if (is_special) {
5922 if (prong_src != .special) continue;
5923 return LazySrcLoc.nodeOffset(
5924 decl.nodeIndexToRelative(case.ast.values[0]),
5925 );
5953 switch (prong_src) {
5954 .special, .special_capture, .special_tag_capture => break case_node,
5955 else => continue,
5956 }
59265957 }
59275958
59285959 const is_multi = case.ast.values.len != 1 or
59295960 node_tags[case.ast.values[0]] == .switch_range;
59305961
59315962 switch (prong_src) {
5932 .scalar => |i| if (!is_multi and i == scalar_i) return LazySrcLoc.nodeOffset(
5933 decl.nodeIndexToRelative(case.ast.values[0]),
5934 ),
5935 .multi_capture => |i| if (is_multi and i == multi_i) {
5936 return LazySrcLoc{ .node_offset_switch_prong_capture = decl.nodeIndexToRelative(case_node) };
5937 },
5938 .multi => |s| if (is_multi and s.prong == multi_i) {
5939 var item_i: u32 = 0;
5940 for (case.ast.values) |item_node| {
5941 if (node_tags[item_node] == .switch_range) continue;
5942
5943 if (item_i == s.item) return LazySrcLoc.nodeOffset(
5944 decl.nodeIndexToRelative(item_node),
5945 );
5946 item_i += 1;
5947 } else unreachable;
5948 },
5949 .range => |s| if (is_multi and s.prong == multi_i) {
5950 var range_i: u32 = 0;
5951 for (case.ast.values) |range| {
5952 if (node_tags[range] != .switch_range) continue;
5953
5954 if (range_i == s.item) switch (range_expand) {
5955 .none => return LazySrcLoc.nodeOffset(
5956 decl.nodeIndexToRelative(range),
5957 ),
5958 .first => return LazySrcLoc.nodeOffset(
5959 decl.nodeIndexToRelative(node_datas[range].lhs),
5960 ),
5961 .last => return LazySrcLoc.nodeOffset(
5962 decl.nodeIndexToRelative(node_datas[range].rhs),
5963 ),
5964 };
5965 range_i += 1;
5966 } else unreachable;
5967 },
5968 .special => {},
5963 .scalar,
5964 .scalar_capture,
5965 .scalar_tag_capture,
5966 => |i| if (!is_multi and i == scalar_i) break case_node,
5967
5968 .multi_capture,
5969 .multi_tag_capture,
5970 => |i| if (is_multi and i == multi_i) break case_node,
5971
5972 .multi,
5973 .range,
5974 => |m| if (is_multi and m.prong == multi_i) break case_node,
5975
5976 .special,
5977 .special_capture,
5978 .special_tag_capture,
5979 => {},
59695980 }
5981
59705982 if (is_multi) {
59715983 multi_i += 1;
59725984 } else {
59735985 scalar_i += 1;
59745986 }
59755987 } else unreachable;
5988
5989 const case = tree.fullSwitchCase(case_node).?;
5990
5991 switch (prong_src) {
5992 .scalar, .special => return LazySrcLoc.nodeOffset(
5993 decl.nodeIndexToRelative(case.ast.values[0]),
5994 ),
5995 .multi => |m| {
5996 var item_i: u32 = 0;
5997 for (case.ast.values) |item_node| {
5998 if (node_tags[item_node] == .switch_range) continue;
5999 if (item_i == m.item) return LazySrcLoc.nodeOffset(
6000 decl.nodeIndexToRelative(item_node),
6001 );
6002 item_i += 1;
6003 }
6004 unreachable;
6005 },
6006 .range => |m| {
6007 var range_i: u32 = 0;
6008 for (case.ast.values) |range| {
6009 if (node_tags[range] != .switch_range) continue;
6010 if (range_i == m.item) switch (range_expand) {
6011 .none => return LazySrcLoc.nodeOffset(
6012 decl.nodeIndexToRelative(range),
6013 ),
6014 .first => return LazySrcLoc.nodeOffset(
6015 decl.nodeIndexToRelative(node_datas[range].lhs),
6016 ),
6017 .last => return LazySrcLoc.nodeOffset(
6018 decl.nodeIndexToRelative(node_datas[range].rhs),
6019 ),
6020 };
6021 range_i += 1;
6022 }
6023 unreachable;
6024 },
6025 .scalar_capture, .multi_capture, .special_capture => {
6026 return .{ .node_offset_switch_prong_capture = decl.nodeIndexToRelative(case_node) };
6027 },
6028 .scalar_tag_capture, .multi_tag_capture, .special_tag_capture => {
6029 return .{ .node_offset_switch_prong_tag_capture = decl.nodeIndexToRelative(case_node) };
6030 },
6031 }
59766032 }
59776033};
59786034
src/Sema.zig+19-13
......@@ -10129,7 +10129,7 @@ const SwitchProngAnalysis = struct {
1012910129 prong_type: enum { normal, special },
1013010130 prong_body: []const Zir.Inst.Index,
1013110131 capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
10132 /// Must use the `scalar`, `special`, or `multi_capture` union field.
10132 /// Must use the `scalar_capture`, `special_capture`, or `multi_capture` union field.
1013310133 raw_capture_src: Module.SwitchProngSrc,
1013410134 /// The set of all values which can reach this prong. May be undefined
1013510135 /// if the prong is special or contains ranges.
......@@ -10247,7 +10247,13 @@ const SwitchProngAnalysis = struct {
1024710247 if (operand_ty.zigTypeTag(mod) != .Union) {
1024810248 const zir_datas = sema.code.instructions.items(.data);
1024910249 const switch_node_offset = zir_datas[spa.switch_block_inst].pl_node.src_node;
10250 const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none);
10250 const raw_tag_capture_src: Module.SwitchProngSrc = switch (raw_capture_src) {
10251 .scalar_capture => |i| .{ .scalar_tag_capture = i },
10252 .multi_capture => |i| .{ .multi_tag_capture = i },
10253 .special_capture => .special_tag_capture,
10254 else => unreachable,
10255 };
10256 const capture_src = raw_tag_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none);
1025110257 const msg = msg: {
1025210258 const msg = try sema.errMsg(block, capture_src, "cannot capture tag of non-union type '{}'", .{
1025310259 operand_ty.fmt(mod),
......@@ -10712,7 +10718,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1071210718 }
1071310719 };
1071410720
10715 const operand = try sema.switchCond(block, src, raw_operand.val);
10721 const operand = try sema.switchCond(block, operand_src, raw_operand.val);
1071610722
1071710723 // AstGen guarantees that the instruction immediately preceding
1071810724 // switch_block(_ref) is a dbg_stmt
......@@ -11377,7 +11383,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1137711383 .normal,
1137811384 body,
1137911385 info.capture,
11380 .{ .scalar = @intCast(u32, scalar_i) },
11386 .{ .scalar_capture = @intCast(u32, scalar_i) },
1138111387 &.{item},
1138211388 if (info.is_inline) operand else .none,
1138311389 info.has_tag_capture,
......@@ -11460,7 +11466,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1146011466 .special,
1146111467 special.body,
1146211468 special.capture,
11463 .special,
11469 .special_capture,
1146411470 undefined, // case_vals may be undefined for special prongs
1146511471 if (special.is_inline) operand else .none,
1146611472 special.has_tag_capture,
......@@ -11491,7 +11497,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1149111497 .special,
1149211498 special.body,
1149311499 special.capture,
11494 .special,
11500 .special_capture,
1149511501 undefined, // case_vals may be undefined for special prongs
1149611502 .none,
1149711503 false,
......@@ -11551,7 +11557,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1155111557 .normal,
1155211558 body,
1155311559 info.capture,
11554 .{ .scalar = @intCast(u32, scalar_i) },
11560 .{ .scalar_capture = @intCast(u32, scalar_i) },
1155511561 &.{item},
1155611562 if (info.is_inline) item else .none,
1155711563 info.has_tag_capture,
......@@ -11885,7 +11891,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1188511891 .special,
1188611892 special.body,
1188711893 special.capture,
11888 .special,
11894 .special_capture,
1188911895 &.{item_ref},
1189011896 item_ref,
1189111897 special.has_tag_capture,
......@@ -11929,7 +11935,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1192911935 .special,
1193011936 special.body,
1193111937 special.capture,
11932 .special,
11938 .special_capture,
1193311939 &.{item_ref},
1193411940 item_ref,
1193511941 special.has_tag_capture,
......@@ -11960,7 +11966,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1196011966 .special,
1196111967 special.body,
1196211968 special.capture,
11963 .special,
11969 .special_capture,
1196411970 &.{item_ref},
1196511971 item_ref,
1196611972 special.has_tag_capture,
......@@ -11988,7 +11994,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1198811994 .special,
1198911995 special.body,
1199011996 special.capture,
11991 .special,
11997 .special_capture,
1199211998 &.{Air.Inst.Ref.bool_true},
1199311999 Air.Inst.Ref.bool_true,
1199412000 special.has_tag_capture,
......@@ -12014,7 +12020,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1201412020 .special,
1201512021 special.body,
1201612022 special.capture,
12017 .special,
12023 .special_capture,
1201812024 &.{Air.Inst.Ref.bool_false},
1201912025 Air.Inst.Ref.bool_false,
1202012026 special.has_tag_capture,
......@@ -12065,7 +12071,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1206512071 .special,
1206612072 special.body,
1206712073 special.capture,
12068 .special,
12074 .special_capture,
1206912075 undefined, // case_vals may be undefined for special prongs
1207012076 .none,
1207112077 false,
test/cases/compile_errors/capture_group_on_switch_prong_with_incompatible_payload_types.zig deleted-21
......@@ -1,21 +0,0 @@
1const Union = union(enum) {
2 A: usize,
3 B: isize,
4};
5comptime {
6 var u = Union{ .A = 8 };
7 switch (u) {
8 .A, .B => |e| {
9 _ = e;
10 unreachable;
11 },
12 }
13}
14
15// error
16// backend=stage2
17// target=native
18//
19// :8:20: error: capture group with incompatible types
20// :8:10: note: type 'usize' here
21// :8:14: note: type 'isize' here
test/cases/compile_errors/switch_on_union_with_no_attached_enum.zig+2-2
......@@ -4,12 +4,12 @@ const Payload = union {
44 C: bool,
55};
66export fn entry() void {
7 const a = Payload { .A = 1234 };
7 const a = Payload{ .A = 1234 };
88 foo(&a);
99}
1010fn foo(a: *const Payload) void {
1111 switch (a.*) {
12 Payload.A => {},
12 .A => {},
1313 else => unreachable,
1414 }
1515}