authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-19 13:19:23+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-21 12:21:30-07:00
log83b2d2cd3eb701b43d17404e73933bc00f7be828
treefae2a1c6e8e32ed4056b59ae639133e207a43916
parent9fb8d21a019deab308a63f7959dab2ee05385969

Sema: better source location for incompatible capture group


4 files changed, 63 insertions(+), 30 deletions(-)

src/Module.zig+28
...@@ -2348,6 +2348,26 @@ pub const SrcLoc = struct {...@@ -2348,6 +2348,26 @@ pub const SrcLoc = struct {
2348 }2348 }
2349 } else unreachable;2349 } else unreachable;
2350 },2350 },
2351 .node_offset_switch_prong_capture => |node_off| {
2352 const tree = try src_loc.file_scope.getTree(gpa);
2353 const case_node = src_loc.declRelativeToNodeIndex(node_off);
2354 const node_tags = tree.nodes.items(.tag);
2355 const case = switch (node_tags[case_node]) {
2356 .switch_case_one => tree.switchCaseOne(case_node),
2357 .switch_case => tree.switchCase(case_node),
2358 else => unreachable,
2359 };
2360 const start_tok = case.payload_token.?;
2361 const token_tags = tree.tokens.items(.tag);
2362 const end_tok = switch (token_tags[start_tok]) {
2363 .asterisk => start_tok + 1,
2364 else => start_tok,
2365 };
2366 const start = tree.tokens.items(.start)[start_tok];
2367 const end_start = tree.tokens.items(.start)[end_tok];
2368 const end = end_start + @intCast(u32, tree.tokenSlice(end_tok).len);
2369 return Span{ .start = start, .end = end, .main = start };
2370 },
2351 .node_offset_fn_type_align => |node_off| {2371 .node_offset_fn_type_align => |node_off| {
2352 const tree = try src_loc.file_scope.getTree(gpa);2372 const tree = try src_loc.file_scope.getTree(gpa);
2353 const node_datas = tree.nodes.items(.data);2373 const node_datas = tree.nodes.items(.data);
...@@ -2877,6 +2897,9 @@ pub const LazySrcLoc = union(enum) {...@@ -2877,6 +2897,9 @@ pub const LazySrcLoc = union(enum) {
2877 /// range nodes. The error applies to all of them.2897 /// range nodes. The error applies to all of them.
2878 /// The Decl is determined contextually.2898 /// The Decl is determined contextually.
2879 node_offset_switch_range: i32,2899 node_offset_switch_range: i32,
2900 /// The source location points to the capture of a switch_prong.
2901 /// The Decl is determined contextually.
2902 node_offset_switch_prong_capture: i32,
2880 /// The source location points to the align expr of a function type2903 /// The source location points to the align expr of a function type
2881 /// expression, found by taking this AST node index offset from the containing2904 /// expression, found by taking this AST node index offset from the containing
2882 /// Decl AST node, which points to a function type AST node. Next, navigate to2905 /// Decl AST node, which points to a function type AST node. Next, navigate to
...@@ -3017,6 +3040,7 @@ pub const LazySrcLoc = union(enum) {...@@ -3017,6 +3040,7 @@ pub const LazySrcLoc = union(enum) {
3017 .node_offset_switch_operand,3040 .node_offset_switch_operand,
3018 .node_offset_switch_special_prong,3041 .node_offset_switch_special_prong,
3019 .node_offset_switch_range,3042 .node_offset_switch_range,
3043 .node_offset_switch_prong_capture,
3020 .node_offset_fn_type_align,3044 .node_offset_fn_type_align,
3021 .node_offset_fn_type_addrspace,3045 .node_offset_fn_type_addrspace,
3022 .node_offset_fn_type_section,3046 .node_offset_fn_type_section,
...@@ -5602,6 +5626,7 @@ pub const SwitchProngSrc = union(enum) {...@@ -5602,6 +5626,7 @@ pub const SwitchProngSrc = union(enum) {
5602 scalar: u32,5626 scalar: u32,
5603 multi: Multi,5627 multi: Multi,
5604 range: Multi,5628 range: Multi,
5629 multi_capture: u32,
56055630
5606 pub const Multi = struct {5631 pub const Multi = struct {
5607 prong: u32,5632 prong: u32,
...@@ -5657,6 +5682,9 @@ pub const SwitchProngSrc = union(enum) {...@@ -5657,6 +5682,9 @@ pub const SwitchProngSrc = union(enum) {
5657 .scalar => |i| if (!is_multi and i == scalar_i) return LazySrcLoc.nodeOffset(5682 .scalar => |i| if (!is_multi and i == scalar_i) return LazySrcLoc.nodeOffset(
5658 decl.nodeIndexToRelative(case.ast.values[0]),5683 decl.nodeIndexToRelative(case.ast.values[0]),
5659 ),5684 ),
5685 .multi_capture => |i| if (is_multi and i == multi_i) {
5686 return LazySrcLoc{ .node_offset_switch_prong_capture = decl.nodeIndexToRelative(case_node) };
5687 },
5660 .multi => |s| if (is_multi and s.prong == multi_i) {5688 .multi => |s| if (is_multi and s.prong == multi_i) {
5661 var item_i: u32 = 0;5689 var item_i: u32 = 0;
5662 for (case.ast.values) |item_node| {5690 for (case.ast.values) |item_node| {
src/Sema.zig+14-9
...@@ -8197,7 +8197,6 @@ fn zirSwitchCapture(...@@ -8197,7 +8197,6 @@ fn zirSwitchCapture(
8197 const switch_info = zir_datas[capture_info.switch_inst].pl_node;8197 const switch_info = zir_datas[capture_info.switch_inst].pl_node;
8198 const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index);8198 const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index);
8199 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_info.src_node };8199 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_info.src_node };
8200 const switch_src = switch_info.src();
8201 const operand_is_ref = switch_extra.data.bits.is_ref;8200 const operand_is_ref = switch_extra.data.bits.is_ref;
8202 const cond_inst = Zir.refToIndex(switch_extra.data.operand).?;8201 const cond_inst = Zir.refToIndex(switch_extra.data.operand).?;
8203 const cond_info = sema.code.instructions.items(.data)[cond_inst].un_node;8202 const cond_info = sema.code.instructions.items(.data)[cond_inst].un_node;
...@@ -8247,7 +8246,7 @@ fn zirSwitchCapture(...@@ -8247,7 +8246,7 @@ fn zirSwitchCapture(
8247 const first_field_index = @intCast(u32, enum_ty.enumTagFieldIndex(first_item_val, sema.mod).?);8246 const first_field_index = @intCast(u32, enum_ty.enumTagFieldIndex(first_item_val, sema.mod).?);
8248 const first_field = union_obj.fields.values()[first_field_index];8247 const first_field = union_obj.fields.values()[first_field_index];
82498248
8250 for (items[1..]) |item| {8249 for (items[1..]) |item, i| {
8251 const item_ref = try sema.resolveInst(item);8250 const item_ref = try sema.resolveInst(item);
8252 // Previous switch validation ensured this will succeed8251 // Previous switch validation ensured this will succeed
8253 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, undefined) catch unreachable;8252 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, undefined) catch unreachable;
...@@ -8255,11 +8254,17 @@ fn zirSwitchCapture(...@@ -8255,11 +8254,17 @@ fn zirSwitchCapture(
8255 const field_index = enum_ty.enumTagFieldIndex(item_val, sema.mod).?;8254 const field_index = enum_ty.enumTagFieldIndex(item_val, sema.mod).?;
8256 const field = union_obj.fields.values()[field_index];8255 const field = union_obj.fields.values()[field_index];
8257 if (!field.ty.eql(first_field.ty, sema.mod)) {8256 if (!field.ty.eql(first_field.ty, sema.mod)) {
8258 const first_item_src = switch_src; // TODO better source location
8259 const item_src = switch_src;
8260 const msg = msg: {8257 const msg = msg: {
8261 const msg = try sema.errMsg(block, switch_src, "capture group with incompatible types", .{});8258 const raw_capture_src = Module.SwitchProngSrc{ .multi_capture = capture_info.prong_index };
8259 const capture_src = raw_capture_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first);
8260
8261 const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{});
8262 errdefer msg.destroy(sema.gpa);8262 errdefer msg.destroy(sema.gpa);
8263
8264 const raw_first_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 0 } };
8265 const first_item_src = raw_first_item_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first);
8266 const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 1 + @intCast(u32, i) } };
8267 const item_src = raw_item_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first);
8263 try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(sema.mod)});8268 try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(sema.mod)});
8264 try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(sema.mod)});8269 try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(sema.mod)});
8265 break :msg msg;8270 break :msg msg;
...@@ -21094,17 +21099,17 @@ const InMemoryCoercionResult = union(enum) {...@@ -21094,17 +21099,17 @@ const InMemoryCoercionResult = union(enum) {
21094 }21099 }
21095 }21100 }
21096 if (!actual_noalias) {21101 if (!actual_noalias) {
21097 try sema.errNote(block, src, msg, "regular paramter {d} cannot cast into a noalias paramter", .{index});21102 try sema.errNote(block, src, msg, "regular parameter {d} cannot cast into a noalias parameter", .{index});
21098 } else {21103 } else {
21099 try sema.errNote(block, src, msg, "noalias paramter {d} cannot cast into a regular paramter", .{index});21104 try sema.errNote(block, src, msg, "noalias parameter {d} cannot cast into a regular parameter", .{index});
21100 }21105 }
21101 break;21106 break;
21102 },21107 },
21103 .fn_param_comptime => |param| {21108 .fn_param_comptime => |param| {
21104 if (param.wanted) {21109 if (param.wanted) {
21105 try sema.errNote(block, src, msg, "non-comptime paramter {d} cannot cast into a comptime paramter", .{param.index});21110 try sema.errNote(block, src, msg, "non-comptime parameter {d} cannot cast into a comptime parameter", .{param.index});
21106 } else {21111 } else {
21107 try sema.errNote(block, src, msg, "comptime paramter {d} cannot cast into a non-comptime paramter", .{param.index});21112 try sema.errNote(block, src, msg, "comptime parameter {d} cannot cast into a non-comptime parameter", .{param.index});
21108 }21113 }
21109 break;21114 break;
21110 },21115 },
test/cases/compile_errors/capture_group_on_switch_prong_with_incompatible_payload_types.zig created+21
...@@ -0,0 +1,21 @@
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/stage1/obj/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=stage1
17// target=native
18//
19// tmp.zig:8:20: error: capture group with incompatible types
20// tmp.zig:8:9: note: type 'usize' here
21// tmp.zig:8:13: note: type 'isize' here