Skip to content

Commit b6f22fc

Browse files
committed
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.
1 parent fb73c7a commit b6f22fc

File tree

4 files changed

+122
-81
lines changed

4 files changed

+122
-81
lines changed

src/Module.zig

Lines changed: 101 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2671,12 +2671,23 @@ pub const SrcLoc = struct {
26712671
}
26722672
} else unreachable;
26732673
},
2674-
.node_offset_switch_prong_capture => |node_off| {
2674+
.node_offset_switch_prong_capture,
2675+
.node_offset_switch_prong_tag_capture,
2676+
=> |node_off| {
26752677
const tree = try src_loc.file_scope.getTree(gpa);
26762678
const case_node = src_loc.declRelativeToNodeIndex(node_off);
26772679
const case = tree.fullSwitchCase(case_node).?;
2678-
const start_tok = case.payload_token.?;
26792680
const token_tags = tree.tokens.items(.tag);
2681+
const start_tok = switch (src_loc.lazy) {
2682+
.node_offset_switch_prong_capture => case.payload_token.?,
2683+
.node_offset_switch_prong_tag_capture => blk: {
2684+
var tok = case.payload_token.?;
2685+
if (token_tags[tok] == .asterisk) tok += 1;
2686+
tok += 2; // skip over comma
2687+
break :blk tok;
2688+
},
2689+
else => unreachable,
2690+
};
26802691
const end_tok = switch (token_tags[start_tok]) {
26812692
.asterisk => start_tok + 1,
26822693
else => start_tok,
@@ -3157,6 +3168,9 @@ pub const LazySrcLoc = union(enum) {
31573168
/// The source location points to the capture of a switch_prong.
31583169
/// The Decl is determined contextually.
31593170
node_offset_switch_prong_capture: i32,
3171+
/// The source location points to the tag capture of a switch_prong.
3172+
/// The Decl is determined contextually.
3173+
node_offset_switch_prong_tag_capture: i32,
31603174
/// The source location points to the align expr of a function type
31613175
/// expression, found by taking this AST node index offset from the containing
31623176
/// Decl AST node, which points to a function type AST node. Next, navigate to
@@ -3330,6 +3344,7 @@ pub const LazySrcLoc = union(enum) {
33303344
.node_offset_switch_special_prong,
33313345
.node_offset_switch_range,
33323346
.node_offset_switch_prong_capture,
3347+
.node_offset_switch_prong_tag_capture,
33333348
.node_offset_fn_type_align,
33343349
.node_offset_fn_type_addrspace,
33353350
.node_offset_fn_type_section,
@@ -6009,11 +6024,26 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void {
60096024
}
60106025

60116026
pub const SwitchProngSrc = union(enum) {
6027+
/// The item for a scalar prong.
60126028
scalar: u32,
6029+
/// A given single item for a multi prong.
60136030
multi: Multi,
6031+
/// A given range item for a multi prong.
60146032
range: Multi,
6015-
multi_capture: u32,
6033+
/// The item for the special prong.
60166034
special,
6035+
/// The main capture for a scalar prong.
6036+
scalar_capture: u32,
6037+
/// The main capture for a multi prong.
6038+
multi_capture: u32,
6039+
/// The main capture for the special prong.
6040+
special_capture,
6041+
/// The tag capture for a scalar prong.
6042+
scalar_tag_capture: u32,
6043+
/// The tag capture for a multi prong.
6044+
multi_tag_capture: u32,
6045+
/// The tag capture for the special prong.
6046+
special_tag_capture,
60176047

60186048
pub const Multi = struct {
60196049
prong: u32,
@@ -6029,6 +6059,7 @@ pub const SwitchProngSrc = union(enum) {
60296059
gpa: Allocator,
60306060
decl: *Decl,
60316061
switch_node_offset: i32,
6062+
/// Ignored if `prong_src` is not `.range`
60326063
range_expand: RangeExpand,
60336064
) LazySrcLoc {
60346065
@setCold(true);
@@ -6048,7 +6079,7 @@ pub const SwitchProngSrc = union(enum) {
60486079

60496080
var multi_i: u32 = 0;
60506081
var scalar_i: u32 = 0;
6051-
for (case_nodes) |case_node| {
6082+
const case_node = for (case_nodes) |case_node| {
60526083
const case = tree.fullSwitchCase(case_node).?;
60536084

60546085
const is_special = special: {
@@ -6060,60 +6091,85 @@ pub const SwitchProngSrc = union(enum) {
60606091
};
60616092

60626093
if (is_special) {
6063-
if (prong_src != .special) continue;
6064-
return LazySrcLoc.nodeOffset(
6065-
decl.nodeIndexToRelative(case.ast.values[0]),
6066-
);
6094+
switch (prong_src) {
6095+
.special, .special_capture, .special_tag_capture => break case_node,
6096+
else => continue,
6097+
}
60676098
}
60686099

60696100
const is_multi = case.ast.values.len != 1 or
60706101
node_tags[case.ast.values[0]] == .switch_range;
60716102

60726103
switch (prong_src) {
6073-
.scalar => |i| if (!is_multi and i == scalar_i) return LazySrcLoc.nodeOffset(
6074-
decl.nodeIndexToRelative(case.ast.values[0]),
6075-
),
6076-
.multi_capture => |i| if (is_multi and i == multi_i) {
6077-
return LazySrcLoc{ .node_offset_switch_prong_capture = decl.nodeIndexToRelative(case_node) };
6078-
},
6079-
.multi => |s| if (is_multi and s.prong == multi_i) {
6080-
var item_i: u32 = 0;
6081-
for (case.ast.values) |item_node| {
6082-
if (node_tags[item_node] == .switch_range) continue;
6083-
6084-
if (item_i == s.item) return LazySrcLoc.nodeOffset(
6085-
decl.nodeIndexToRelative(item_node),
6086-
);
6087-
item_i += 1;
6088-
} else unreachable;
6089-
},
6090-
.range => |s| if (is_multi and s.prong == multi_i) {
6091-
var range_i: u32 = 0;
6092-
for (case.ast.values) |range| {
6093-
if (node_tags[range] != .switch_range) continue;
6094-
6095-
if (range_i == s.item) switch (range_expand) {
6096-
.none => return LazySrcLoc.nodeOffset(
6097-
decl.nodeIndexToRelative(range),
6098-
),
6099-
.first => return LazySrcLoc.nodeOffset(
6100-
decl.nodeIndexToRelative(node_datas[range].lhs),
6101-
),
6102-
.last => return LazySrcLoc.nodeOffset(
6103-
decl.nodeIndexToRelative(node_datas[range].rhs),
6104-
),
6105-
};
6106-
range_i += 1;
6107-
} else unreachable;
6108-
},
6109-
.special => {},
6104+
.scalar,
6105+
.scalar_capture,
6106+
.scalar_tag_capture,
6107+
=> |i| if (!is_multi and i == scalar_i) break case_node,
6108+
6109+
.multi_capture,
6110+
.multi_tag_capture,
6111+
=> |i| if (is_multi and i == multi_i) break case_node,
6112+
6113+
.multi,
6114+
.range,
6115+
=> |m| if (is_multi and m.prong == multi_i) break case_node,
6116+
6117+
.special,
6118+
.special_capture,
6119+
.special_tag_capture,
6120+
=> {},
61106121
}
6122+
61116123
if (is_multi) {
61126124
multi_i += 1;
61136125
} else {
61146126
scalar_i += 1;
61156127
}
61166128
} else unreachable;
6129+
6130+
const case = tree.fullSwitchCase(case_node).?;
6131+
6132+
switch (prong_src) {
6133+
.scalar, .special => return LazySrcLoc.nodeOffset(
6134+
decl.nodeIndexToRelative(case.ast.values[0]),
6135+
),
6136+
.multi => |m| {
6137+
var item_i: u32 = 0;
6138+
for (case.ast.values) |item_node| {
6139+
if (node_tags[item_node] == .switch_range) continue;
6140+
if (item_i == m.item) return LazySrcLoc.nodeOffset(
6141+
decl.nodeIndexToRelative(item_node),
6142+
);
6143+
item_i += 1;
6144+
}
6145+
unreachable;
6146+
},
6147+
.range => |m| {
6148+
var range_i: u32 = 0;
6149+
for (case.ast.values) |range| {
6150+
if (node_tags[range] != .switch_range) continue;
6151+
if (range_i == m.item) switch (range_expand) {
6152+
.none => return LazySrcLoc.nodeOffset(
6153+
decl.nodeIndexToRelative(range),
6154+
),
6155+
.first => return LazySrcLoc.nodeOffset(
6156+
decl.nodeIndexToRelative(node_datas[range].lhs),
6157+
),
6158+
.last => return LazySrcLoc.nodeOffset(
6159+
decl.nodeIndexToRelative(node_datas[range].rhs),
6160+
),
6161+
};
6162+
range_i += 1;
6163+
}
6164+
unreachable;
6165+
},
6166+
.scalar_capture, .multi_capture, .special_capture => {
6167+
return .{ .node_offset_switch_prong_capture = decl.nodeIndexToRelative(case_node) };
6168+
},
6169+
.scalar_tag_capture, .multi_tag_capture, .special_tag_capture => {
6170+
return .{ .node_offset_switch_prong_tag_capture = decl.nodeIndexToRelative(case_node) };
6171+
},
6172+
}
61176173
}
61186174
};
61196175

src/Sema.zig

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10098,7 +10098,7 @@ const SwitchProngAnalysis = struct {
1009810098
prong_type: enum { normal, special },
1009910099
prong_body: []const Zir.Inst.Index,
1010010100
capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
10101-
/// Must use the `scalar`, `special`, or `multi_capture` union field.
10101+
/// Must use the `scalar_capture`, `special_capture`, or `multi_capture` union field.
1010210102
raw_capture_src: Module.SwitchProngSrc,
1010310103
/// The set of all values which can reach this prong. May be undefined
1010410104
/// if the prong is special or contains ranges.
@@ -10215,7 +10215,13 @@ const SwitchProngAnalysis = struct {
1021510215
if (operand_ty.zigTypeTag() != .Union) {
1021610216
const zir_datas = sema.code.instructions.items(.data);
1021710217
const switch_node_offset = zir_datas[spa.switch_block_inst].pl_node.src_node;
10218-
const capture_src = raw_capture_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_node_offset, .none);
10218+
const raw_tag_capture_src: Module.SwitchProngSrc = switch (raw_capture_src) {
10219+
.scalar_capture => |i| .{ .scalar_tag_capture = i },
10220+
.multi_capture => |i| .{ .multi_tag_capture = i },
10221+
.special_capture => .special_tag_capture,
10222+
else => unreachable,
10223+
};
10224+
const capture_src = raw_tag_capture_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_node_offset, .none);
1021910225
const msg = msg: {
1022010226
const msg = try sema.errMsg(block, capture_src, "cannot capture tag of non-union type '{}'", .{
1022110227
operand_ty.fmt(sema.mod),
@@ -10679,7 +10685,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1067910685
}
1068010686
};
1068110687

10682-
const operand = try sema.switchCond(block, src, raw_operand.val);
10688+
const operand = try sema.switchCond(block, operand_src, raw_operand.val);
1068310689

1068410690
// AstGen guarantees that the instruction immediately preceding
1068510691
// switch_block(_ref) is a dbg_stmt
@@ -11352,7 +11358,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1135211358
.normal,
1135311359
body,
1135411360
info.capture,
11355-
.{ .scalar = @intCast(u32, scalar_i) },
11361+
.{ .scalar_capture = @intCast(u32, scalar_i) },
1135611362
&.{item},
1135711363
if (info.is_inline) operand else .none,
1135811364
info.has_tag_capture,
@@ -11435,7 +11441,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1143511441
.special,
1143611442
special.body,
1143711443
special.capture,
11438-
.special,
11444+
.special_capture,
1143911445
undefined, // case_vals may be undefined for special prongs
1144011446
if (special.is_inline) operand else .none,
1144111447
special.has_tag_capture,
@@ -11466,7 +11472,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1146611472
.special,
1146711473
special.body,
1146811474
special.capture,
11469-
.special,
11475+
.special_capture,
1147011476
undefined, // case_vals may be undefined for special prongs
1147111477
.none,
1147211478
false,
@@ -11526,7 +11532,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1152611532
.normal,
1152711533
body,
1152811534
info.capture,
11529-
.{ .scalar = @intCast(u32, scalar_i) },
11535+
.{ .scalar_capture = @intCast(u32, scalar_i) },
1153011536
&.{item},
1153111537
if (info.is_inline) item else .none,
1153211538
info.has_tag_capture,
@@ -11857,7 +11863,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1185711863
.special,
1185811864
special.body,
1185911865
special.capture,
11860-
.special,
11866+
.special_capture,
1186111867
&.{item_ref},
1186211868
item_ref,
1186311869
special.has_tag_capture,
@@ -11897,7 +11903,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1189711903
.special,
1189811904
special.body,
1189911905
special.capture,
11900-
.special,
11906+
.special_capture,
1190111907
&.{item_ref},
1190211908
item_ref,
1190311909
special.has_tag_capture,
@@ -11928,7 +11934,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1192811934
.special,
1192911935
special.body,
1193011936
special.capture,
11931-
.special,
11937+
.special_capture,
1193211938
&.{item_ref},
1193311939
item_ref,
1193411940
special.has_tag_capture,
@@ -11956,7 +11962,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1195611962
.special,
1195711963
special.body,
1195811964
special.capture,
11959-
.special,
11965+
.special_capture,
1196011966
&.{Air.Inst.Ref.bool_true},
1196111967
Air.Inst.Ref.bool_true,
1196211968
special.has_tag_capture,
@@ -11982,7 +11988,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1198211988
.special,
1198311989
special.body,
1198411990
special.capture,
11985-
.special,
11991+
.special_capture,
1198611992
&.{Air.Inst.Ref.bool_false},
1198711993
Air.Inst.Ref.bool_false,
1198811994
special.has_tag_capture,
@@ -12033,7 +12039,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1203312039
.special,
1203412040
special.body,
1203512041
special.capture,
12036-
.special,
12042+
.special_capture,
1203712043
undefined, // case_vals may be undefined for special prongs
1203812044
.none,
1203912045
false,

test/cases/compile_errors/capture_group_on_switch_prong_with_incompatible_payload_types.zig

Lines changed: 0 additions & 21 deletions
This file was deleted.

test/cases/compile_errors/switch_on_union_with_no_attached_enum.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ const Payload = union {
44
C: bool,
55
};
66
export fn entry() void {
7-
const a = Payload { .A = 1234 };
7+
const a = Payload{ .A = 1234 };
88
foo(&a);
99
}
1010
fn foo(a: *const Payload) void {
1111
switch (a.*) {
12-
Payload.A => {},
12+
.A => {},
1313
else => unreachable,
1414
}
1515
}

0 commit comments

Comments
 (0)