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 {...@@ -2471,12 +2471,23 @@ pub const SrcLoc = struct {
2471 }2471 }
2472 } else unreachable;2472 } else unreachable;
2473 },2473 },
2474 .node_offset_switch_prong_capture => |node_off| {2474 .node_offset_switch_prong_capture,
2475 .node_offset_switch_prong_tag_capture,
2476 => |node_off| {
2475 const tree = try src_loc.file_scope.getTree(gpa);2477 const tree = try src_loc.file_scope.getTree(gpa);
2476 const case_node = src_loc.declRelativeToNodeIndex(node_off);2478 const case_node = src_loc.declRelativeToNodeIndex(node_off);
2477 const case = tree.fullSwitchCase(case_node).?;2479 const case = tree.fullSwitchCase(case_node).?;
2478 const start_tok = case.payload_token.?;
2479 const token_tags = tree.tokens.items(.tag);2480 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 };
2480 const end_tok = switch (token_tags[start_tok]) {2491 const end_tok = switch (token_tags[start_tok]) {
2481 .asterisk => start_tok + 1,2492 .asterisk => start_tok + 1,
2482 else => start_tok,2493 else => start_tok,
...@@ -2957,6 +2968,9 @@ pub const LazySrcLoc = union(enum) {...@@ -2957,6 +2968,9 @@ pub const LazySrcLoc = union(enum) {
2957 /// The source location points to the capture of a switch_prong.2968 /// The source location points to the capture of a switch_prong.
2958 /// The Decl is determined contextually.2969 /// The Decl is determined contextually.
2959 node_offset_switch_prong_capture: i32,2970 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,
2960 /// The source location points to the align expr of a function type2974 /// The source location points to the align expr of a function type
2961 /// expression, found by taking this AST node index offset from the containing2975 /// expression, found by taking this AST node index offset from the containing
2962 /// Decl AST node, which points to a function type AST node. Next, navigate to2976 /// Decl AST node, which points to a function type AST node. Next, navigate to
...@@ -3130,6 +3144,7 @@ pub const LazySrcLoc = union(enum) {...@@ -3130,6 +3144,7 @@ pub const LazySrcLoc = union(enum) {
3130 .node_offset_switch_special_prong,3144 .node_offset_switch_special_prong,
3131 .node_offset_switch_range,3145 .node_offset_switch_range,
3132 .node_offset_switch_prong_capture,3146 .node_offset_switch_prong_capture,
3147 .node_offset_switch_prong_tag_capture,
3133 .node_offset_fn_type_align,3148 .node_offset_fn_type_align,
3134 .node_offset_fn_type_addrspace,3149 .node_offset_fn_type_addrspace,
3135 .node_offset_fn_type_section,3150 .node_offset_fn_type_section,
...@@ -5867,11 +5882,26 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void {...@@ -5867,11 +5882,26 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void {
5867}5882}
58685883
5869pub const SwitchProngSrc = union(enum) {5884pub const SwitchProngSrc = union(enum) {
5885 /// The item for a scalar prong.
5870 scalar: u32,5886 scalar: u32,
5887 /// A given single item for a multi prong.
5871 multi: Multi,5888 multi: Multi,
5889 /// A given range item for a multi prong.
5872 range: Multi,5890 range: Multi,
5873 multi_capture: u32,5891 /// The item for the special prong.
5874 special,5892 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
5876 pub const Multi = struct {5906 pub const Multi = struct {
5877 prong: u32,5907 prong: u32,
...@@ -5887,6 +5917,7 @@ pub const SwitchProngSrc = union(enum) {...@@ -5887,6 +5917,7 @@ pub const SwitchProngSrc = union(enum) {
5887 mod: *Module,5917 mod: *Module,
5888 decl: *Decl,5918 decl: *Decl,
5889 switch_node_offset: i32,5919 switch_node_offset: i32,
5920 /// Ignored if `prong_src` is not `.range`
5890 range_expand: RangeExpand,5921 range_expand: RangeExpand,
5891 ) LazySrcLoc {5922 ) LazySrcLoc {
5892 @setCold(true);5923 @setCold(true);
...@@ -5907,7 +5938,7 @@ pub const SwitchProngSrc = union(enum) {...@@ -5907,7 +5938,7 @@ pub const SwitchProngSrc = union(enum) {
59075938
5908 var multi_i: u32 = 0;5939 var multi_i: u32 = 0;
5909 var scalar_i: u32 = 0;5940 var scalar_i: u32 = 0;
5910 for (case_nodes) |case_node| {5941 const case_node = for (case_nodes) |case_node| {
5911 const case = tree.fullSwitchCase(case_node).?;5942 const case = tree.fullSwitchCase(case_node).?;
59125943
5913 const is_special = special: {5944 const is_special = special: {
...@@ -5919,60 +5950,85 @@ pub const SwitchProngSrc = union(enum) {...@@ -5919,60 +5950,85 @@ pub const SwitchProngSrc = union(enum) {
5919 };5950 };
59205951
5921 if (is_special) {5952 if (is_special) {
5922 if (prong_src != .special) continue;5953 switch (prong_src) {
5923 return LazySrcLoc.nodeOffset(5954 .special, .special_capture, .special_tag_capture => break case_node,
5924 decl.nodeIndexToRelative(case.ast.values[0]),5955 else => continue,
5925 );5956 }
5926 }5957 }
59275958
5928 const is_multi = case.ast.values.len != 1 or5959 const is_multi = case.ast.values.len != 1 or
5929 node_tags[case.ast.values[0]] == .switch_range;5960 node_tags[case.ast.values[0]] == .switch_range;
59305961
5931 switch (prong_src) {5962 switch (prong_src) {
5932 .scalar => |i| if (!is_multi and i == scalar_i) return LazySrcLoc.nodeOffset(5963 .scalar,
5933 decl.nodeIndexToRelative(case.ast.values[0]),5964 .scalar_capture,
5934 ),5965 .scalar_tag_capture,
5935 .multi_capture => |i| if (is_multi and i == multi_i) {5966 => |i| if (!is_multi and i == scalar_i) break case_node,
5936 return LazySrcLoc{ .node_offset_switch_prong_capture = decl.nodeIndexToRelative(case_node) };5967
5937 },5968 .multi_capture,
5938 .multi => |s| if (is_multi and s.prong == multi_i) {5969 .multi_tag_capture,
5939 var item_i: u32 = 0;5970 => |i| if (is_multi and i == multi_i) break case_node,
5940 for (case.ast.values) |item_node| {5971
5941 if (node_tags[item_node] == .switch_range) continue;5972 .multi,
59425973 .range,
5943 if (item_i == s.item) return LazySrcLoc.nodeOffset(5974 => |m| if (is_multi and m.prong == multi_i) break case_node,
5944 decl.nodeIndexToRelative(item_node),5975
5945 );5976 .special,
5946 item_i += 1;5977 .special_capture,
5947 } else unreachable;5978 .special_tag_capture,
5948 },5979 => {},
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 => {},
5969 }5980 }
5981
5970 if (is_multi) {5982 if (is_multi) {
5971 multi_i += 1;5983 multi_i += 1;
5972 } else {5984 } else {
5973 scalar_i += 1;5985 scalar_i += 1;
5974 }5986 }
5975 } else unreachable;5987 } 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 }
5976 }6032 }
5977};6033};
59786034
src/Sema.zig+19-13
...@@ -10129,7 +10129,7 @@ const SwitchProngAnalysis = struct {...@@ -10129,7 +10129,7 @@ const SwitchProngAnalysis = struct {
10129 prong_type: enum { normal, special },10129 prong_type: enum { normal, special },
10130 prong_body: []const Zir.Inst.Index,10130 prong_body: []const Zir.Inst.Index,
10131 capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,10131 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.
10133 raw_capture_src: Module.SwitchProngSrc,10133 raw_capture_src: Module.SwitchProngSrc,
10134 /// The set of all values which can reach this prong. May be undefined10134 /// The set of all values which can reach this prong. May be undefined
10135 /// if the prong is special or contains ranges.10135 /// if the prong is special or contains ranges.
...@@ -10247,7 +10247,13 @@ const SwitchProngAnalysis = struct {...@@ -10247,7 +10247,13 @@ const SwitchProngAnalysis = struct {
10247 if (operand_ty.zigTypeTag(mod) != .Union) {10247 if (operand_ty.zigTypeTag(mod) != .Union) {
10248 const zir_datas = sema.code.instructions.items(.data);10248 const zir_datas = sema.code.instructions.items(.data);
10249 const switch_node_offset = zir_datas[spa.switch_block_inst].pl_node.src_node;10249 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);
10251 const msg = msg: {10257 const msg = msg: {
10252 const msg = try sema.errMsg(block, capture_src, "cannot capture tag of non-union type '{}'", .{10258 const msg = try sema.errMsg(block, capture_src, "cannot capture tag of non-union type '{}'", .{
10253 operand_ty.fmt(mod),10259 operand_ty.fmt(mod),
...@@ -10712,7 +10718,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r...@@ -10712,7 +10718,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
10712 }10718 }
10713 };10719 };
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
10717 // AstGen guarantees that the instruction immediately preceding10723 // AstGen guarantees that the instruction immediately preceding
10718 // switch_block(_ref) is a dbg_stmt10724 // switch_block(_ref) is a dbg_stmt
...@@ -11377,7 +11383,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r...@@ -11377,7 +11383,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
11377 .normal,11383 .normal,
11378 body,11384 body,
11379 info.capture,11385 info.capture,
11380 .{ .scalar = @intCast(u32, scalar_i) },11386 .{ .scalar_capture = @intCast(u32, scalar_i) },
11381 &.{item},11387 &.{item},
11382 if (info.is_inline) operand else .none,11388 if (info.is_inline) operand else .none,
11383 info.has_tag_capture,11389 info.has_tag_capture,
...@@ -11460,7 +11466,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r...@@ -11460,7 +11466,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
11460 .special,11466 .special,
11461 special.body,11467 special.body,
11462 special.capture,11468 special.capture,
11463 .special,11469 .special_capture,
11464 undefined, // case_vals may be undefined for special prongs11470 undefined, // case_vals may be undefined for special prongs
11465 if (special.is_inline) operand else .none,11471 if (special.is_inline) operand else .none,
11466 special.has_tag_capture,11472 special.has_tag_capture,
...@@ -11491,7 +11497,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r...@@ -11491,7 +11497,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
11491 .special,11497 .special,
11492 special.body,11498 special.body,
11493 special.capture,11499 special.capture,
11494 .special,11500 .special_capture,
11495 undefined, // case_vals may be undefined for special prongs11501 undefined, // case_vals may be undefined for special prongs
11496 .none,11502 .none,
11497 false,11503 false,
...@@ -11551,7 +11557,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r...@@ -11551,7 +11557,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
11551 .normal,11557 .normal,
11552 body,11558 body,
11553 info.capture,11559 info.capture,
11554 .{ .scalar = @intCast(u32, scalar_i) },11560 .{ .scalar_capture = @intCast(u32, scalar_i) },
11555 &.{item},11561 &.{item},
11556 if (info.is_inline) item else .none,11562 if (info.is_inline) item else .none,
11557 info.has_tag_capture,11563 info.has_tag_capture,
...@@ -11885,7 +11891,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r...@@ -11885,7 +11891,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
11885 .special,11891 .special,
11886 special.body,11892 special.body,
11887 special.capture,11893 special.capture,
11888 .special,11894 .special_capture,
11889 &.{item_ref},11895 &.{item_ref},
11890 item_ref,11896 item_ref,
11891 special.has_tag_capture,11897 special.has_tag_capture,
...@@ -11929,7 +11935,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r...@@ -11929,7 +11935,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
11929 .special,11935 .special,
11930 special.body,11936 special.body,
11931 special.capture,11937 special.capture,
11932 .special,11938 .special_capture,
11933 &.{item_ref},11939 &.{item_ref},
11934 item_ref,11940 item_ref,
11935 special.has_tag_capture,11941 special.has_tag_capture,
...@@ -11960,7 +11966,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r...@@ -11960,7 +11966,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
11960 .special,11966 .special,
11961 special.body,11967 special.body,
11962 special.capture,11968 special.capture,
11963 .special,11969 .special_capture,
11964 &.{item_ref},11970 &.{item_ref},
11965 item_ref,11971 item_ref,
11966 special.has_tag_capture,11972 special.has_tag_capture,
...@@ -11988,7 +11994,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r...@@ -11988,7 +11994,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
11988 .special,11994 .special,
11989 special.body,11995 special.body,
11990 special.capture,11996 special.capture,
11991 .special,11997 .special_capture,
11992 &.{Air.Inst.Ref.bool_true},11998 &.{Air.Inst.Ref.bool_true},
11993 Air.Inst.Ref.bool_true,11999 Air.Inst.Ref.bool_true,
11994 special.has_tag_capture,12000 special.has_tag_capture,
...@@ -12014,7 +12020,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r...@@ -12014,7 +12020,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
12014 .special,12020 .special,
12015 special.body,12021 special.body,
12016 special.capture,12022 special.capture,
12017 .special,12023 .special_capture,
12018 &.{Air.Inst.Ref.bool_false},12024 &.{Air.Inst.Ref.bool_false},
12019 Air.Inst.Ref.bool_false,12025 Air.Inst.Ref.bool_false,
12020 special.has_tag_capture,12026 special.has_tag_capture,
...@@ -12065,7 +12071,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r...@@ -12065,7 +12071,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
12065 .special,12071 .special,
12066 special.body,12072 special.body,
12067 special.capture,12073 special.capture,
12068 .special,12074 .special_capture,
12069 undefined, // case_vals may be undefined for special prongs12075 undefined, // case_vals may be undefined for special prongs
12070 .none,12076 .none,
12071 false,12077 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 {...@@ -4,12 +4,12 @@ const Payload = union {
4 C: bool,4 C: bool,
5};5};
6export fn entry() void {6export fn entry() void {
7 const a = Payload { .A = 1234 };7 const a = Payload{ .A = 1234 };
8 foo(&a);8 foo(&a);
9}9}
10fn foo(a: *const Payload) void {10fn foo(a: *const Payload) void {
11 switch (a.*) {11 switch (a.*) {
12 Payload.A => {},12 .A => {},
13 else => unreachable,13 else => unreachable,
14 }14 }
15}15}