authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-18 12:26:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-18 19:17:21-07:00
log22965e6fcbafbcba207a6da8eb493af2cf7ef924
tree99f420ce5880d23f3053fbf52e977f1cf6715a83
parentb13745ac03195c87d9efec2b12f564d4d3cbd477

Sema: improve error message for mismatched for loop lengths


3 files changed, 52 insertions(+), 4 deletions(-)

src/Module.zig+16
......@@ -2462,6 +2462,13 @@ pub const SrcLoc = struct {
24622462 };
24632463 return nodeToSpan(tree, src_node);
24642464 },
2465 .for_input => |for_input| {
2466 const tree = try src_loc.file_scope.getTree(gpa);
2467 const node = src_loc.declRelativeToNodeIndex(for_input.for_node_offset);
2468 const for_full = tree.fullFor(node).?;
2469 const src_node = for_full.ast.inputs[for_input.input_index];
2470 return nodeToSpan(tree, src_node);
2471 },
24652472 .node_offset_bin_lhs => |node_off| {
24662473 const tree = try src_loc.file_scope.getTree(gpa);
24672474 const node = src_loc.declRelativeToNodeIndex(node_off);
......@@ -3114,6 +3121,14 @@ pub const LazySrcLoc = union(enum) {
31143121 /// The source location points to the RHS of an assignment.
31153122 /// The Decl is determined contextually.
31163123 node_offset_store_operand: i32,
3124 /// The source location points to a for loop input.
3125 /// The Decl is determined contextually.
3126 for_input: struct {
3127 /// Points to the for loop AST node.
3128 for_node_offset: i32,
3129 /// Picks one of the inputs from the condition.
3130 input_index: u32,
3131 },
31173132
31183133 pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
31193134
......@@ -3200,6 +3215,7 @@ pub const LazySrcLoc = union(enum) {
32003215 .node_offset_init_ty,
32013216 .node_offset_store_ptr,
32023217 .node_offset_store_operand,
3218 .for_input,
32033219 => .{
32043220 .file_scope = decl.getFileScope(),
32053221 .parent_decl_node = decl.src_node,
src/Sema.zig+23-4
......@@ -3910,14 +3910,15 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
39103910
39113911 var len: Air.Inst.Ref = .none;
39123912 var len_val: ?Value = null;
3913 var len_idx: usize = undefined;
3913 var len_idx: u32 = undefined;
39143914 var any_runtime = false;
39153915
39163916 const runtime_arg_lens = try gpa.alloc(Air.Inst.Ref, args.len);
39173917 defer gpa.free(runtime_arg_lens);
39183918
39193919 // First pass to look for comptime values.
3920 for (args, 0..) |zir_arg, i| {
3920 for (args, 0..) |zir_arg, i_usize| {
3921 const i = @intCast(u32, i_usize);
39213922 runtime_arg_lens[i] = .none;
39223923 if (zir_arg == .none) continue;
39233924 const object = try sema.resolveInst(zir_arg);
......@@ -3941,8 +3942,26 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
39413942 if (try sema.resolveDefinedValue(block, src, arg_len)) |arg_val| {
39423943 if (len_val) |v| {
39433944 if (!(try sema.valuesEqual(arg_val, v, Type.usize))) {
3944 // TODO error notes for each arg stating the differing values
3945 return sema.fail(block, src, "non-matching for loop lengths", .{});
3945 const msg = msg: {
3946 const msg = try sema.errMsg(block, src, "non-matching for loop lengths", .{});
3947 errdefer msg.destroy(gpa);
3948 const a_src: LazySrcLoc = .{ .for_input = .{
3949 .for_node_offset = inst_data.src_node,
3950 .input_index = len_idx,
3951 } };
3952 const b_src: LazySrcLoc = .{ .for_input = .{
3953 .for_node_offset = inst_data.src_node,
3954 .input_index = i,
3955 } };
3956 try sema.errNote(block, a_src, msg, "length {} here", .{
3957 v.fmtValue(Type.usize, sema.mod),
3958 });
3959 try sema.errNote(block, b_src, msg, "length {} here", .{
3960 arg_val.fmtValue(Type.usize, sema.mod),
3961 });
3962 break :msg msg;
3963 };
3964 return sema.failWithOwnedErrorMsg(msg);
39463965 }
39473966 } else {
39483967 len = arg_len;
test/cases/compile_errors/for.zig created+13
......@@ -0,0 +1,13 @@
1export fn a() void {
2 for (0..10, 10..21) |i, j| {
3 _ = i; _ = j;
4 }
5}
6
7// error
8// backend=stage2
9// target=native
10//
11// :2:5: error: non-matching for loop lengths
12// :2:11: note: length 10 here
13// :2:19: note: length 11 here