Skip to content

Commit 42dc753

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 bcb673d commit 42dc753

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
@@ -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

58695884
pub 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

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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

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)