From aeaef8c0ffadab4145fd002f2edd87a6db66ebd1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 18 Feb 2023 09:02:57 -0700 Subject: update std lib and compiler sources to new for loop syntax --- src/Module.zig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/Module.zig') diff --git a/src/Module.zig b/src/Module.zig index a129cb0cb6..4feb04abdd 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -268,7 +268,7 @@ pub const MemoizedCall = struct { if (a.func != b.func) return false; assert(a.args.len == b.args.len); - for (a.args) |a_arg, arg_i| { + for (a.args, 0..) |a_arg, arg_i| { const b_arg = b.args[arg_i]; if (!a_arg.eql(b_arg, ctx.module)) { return false; @@ -1082,7 +1082,7 @@ pub const Struct = struct { assert(s.layout == .Packed); assert(s.haveLayout()); var bit_sum: u64 = 0; - for (s.fields.values()) |field, i| { + for (s.fields.values(), 0..) |field, i| { if (i == index) { return @intCast(u16, bit_sum); } @@ -1341,7 +1341,7 @@ pub const Union = struct { assert(u.haveFieldTypes()); var most_alignment: u32 = 0; var most_index: usize = undefined; - for (u.fields.values()) |field, i| { + for (u.fields.values(), 0..) |field, i| { if (!field.ty.hasRuntimeBits()) continue; const field_align = field.normalAlignment(target); @@ -1405,7 +1405,7 @@ pub const Union = struct { var payload_size: u64 = 0; var payload_align: u32 = 0; const fields = u.fields.values(); - for (fields) |field, i| { + for (fields, 0..) |field, i| { if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue; const field_align = a: { @@ -3553,7 +3553,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void { } if (data_has_safety_tag) { const tags = zir.instructions.items(.tag); - for (zir.instructions.items(.data)) |*data, i| { + for (zir.instructions.items(.data), 0..) |*data, i| { const union_tag = Zir.Inst.Tag.data_tags[@enumToInt(tags[i])]; const as_struct = @ptrCast(*HackDataLayout, data); as_struct.* = .{ @@ -3740,7 +3740,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void { @ptrCast([*]const u8, file.zir.instructions.items(.data).ptr); if (data_has_safety_tag) { // The `Data` union has a safety tag but in the file format we store it without. - for (file.zir.instructions.items(.data)) |*data, i| { + for (file.zir.instructions.items(.data), 0..) |*data, i| { const as_struct = @ptrCast(*const HackDataLayout, data); safety_buffer[i] = as_struct.data; } @@ -6293,7 +6293,7 @@ pub fn populateTestFunctions( // Add a dependency on each test name and function pointer. try array_decl.dependencies.ensureUnusedCapacity(gpa, test_fn_vals.len * 2); - for (mod.test_functions.keys()) |test_decl_index, i| { + for (mod.test_functions.keys(), 0..) |test_decl_index, i| { const test_decl = mod.declPtr(test_decl_index); const test_name_slice = mem.sliceTo(test_decl.name, 0); const test_name_decl_index = n: { -- cgit v1.2.3 From 22965e6fcbafbcba207a6da8eb493af2cf7ef924 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 18 Feb 2023 12:26:22 -0700 Subject: Sema: improve error message for mismatched for loop lengths --- src/Module.zig | 16 ++++++++++++++++ src/Sema.zig | 27 +++++++++++++++++++++++---- test/cases/compile_errors/for.zig | 13 +++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 test/cases/compile_errors/for.zig (limited to 'src/Module.zig') diff --git a/src/Module.zig b/src/Module.zig index 4feb04abdd..377ccd2441 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -2462,6 +2462,13 @@ pub const SrcLoc = struct { }; return nodeToSpan(tree, src_node); }, + .for_input => |for_input| { + const tree = try src_loc.file_scope.getTree(gpa); + const node = src_loc.declRelativeToNodeIndex(for_input.for_node_offset); + const for_full = tree.fullFor(node).?; + const src_node = for_full.ast.inputs[for_input.input_index]; + return nodeToSpan(tree, src_node); + }, .node_offset_bin_lhs => |node_off| { const tree = try src_loc.file_scope.getTree(gpa); const node = src_loc.declRelativeToNodeIndex(node_off); @@ -3114,6 +3121,14 @@ pub const LazySrcLoc = union(enum) { /// The source location points to the RHS of an assignment. /// The Decl is determined contextually. node_offset_store_operand: i32, + /// The source location points to a for loop input. + /// The Decl is determined contextually. + for_input: struct { + /// Points to the for loop AST node. + for_node_offset: i32, + /// Picks one of the inputs from the condition. + input_index: u32, + }, pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease; @@ -3200,6 +3215,7 @@ pub const LazySrcLoc = union(enum) { .node_offset_init_ty, .node_offset_store_ptr, .node_offset_store_operand, + .for_input, => .{ .file_scope = decl.getFileScope(), .parent_decl_node = decl.src_node, diff --git a/src/Sema.zig b/src/Sema.zig index 980aee720b..5a185a709c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3910,14 +3910,15 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. var len: Air.Inst.Ref = .none; var len_val: ?Value = null; - var len_idx: usize = undefined; + var len_idx: u32 = undefined; var any_runtime = false; const runtime_arg_lens = try gpa.alloc(Air.Inst.Ref, args.len); defer gpa.free(runtime_arg_lens); // First pass to look for comptime values. - for (args, 0..) |zir_arg, i| { + for (args, 0..) |zir_arg, i_usize| { + const i = @intCast(u32, i_usize); runtime_arg_lens[i] = .none; if (zir_arg == .none) continue; const object = try sema.resolveInst(zir_arg); @@ -3941,8 +3942,26 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. if (try sema.resolveDefinedValue(block, src, arg_len)) |arg_val| { if (len_val) |v| { if (!(try sema.valuesEqual(arg_val, v, Type.usize))) { - // TODO error notes for each arg stating the differing values - return sema.fail(block, src, "non-matching for loop lengths", .{}); + const msg = msg: { + const msg = try sema.errMsg(block, src, "non-matching for loop lengths", .{}); + errdefer msg.destroy(gpa); + const a_src: LazySrcLoc = .{ .for_input = .{ + .for_node_offset = inst_data.src_node, + .input_index = len_idx, + } }; + const b_src: LazySrcLoc = .{ .for_input = .{ + .for_node_offset = inst_data.src_node, + .input_index = i, + } }; + try sema.errNote(block, a_src, msg, "length {} here", .{ + v.fmtValue(Type.usize, sema.mod), + }); + try sema.errNote(block, b_src, msg, "length {} here", .{ + arg_val.fmtValue(Type.usize, sema.mod), + }); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); } } else { len = arg_len; diff --git a/test/cases/compile_errors/for.zig b/test/cases/compile_errors/for.zig new file mode 100644 index 0000000000..999782c991 --- /dev/null +++ b/test/cases/compile_errors/for.zig @@ -0,0 +1,13 @@ +export fn a() void { + for (0..10, 10..21) |i, j| { + _ = i; _ = j; + } +} + +// error +// backend=stage2 +// target=native +// +// :2:5: error: non-matching for loop lengths +// :2:11: note: length 10 here +// :2:19: note: length 11 here -- cgit v1.2.3 From 4dd958d585256df3119d5617d22492f41ed02884 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 18 Feb 2023 14:10:56 -0700 Subject: improve error message for byref capture of byval array --- lib/std/crypto/aes/soft.zig | 2 +- src/Module.zig | 49 +++++++++++++++++++++++++++++++++++++++ src/Sema.zig | 22 +++++++++++++----- test/cases/compile_errors/for.zig | 8 +++++++ 4 files changed, 74 insertions(+), 7 deletions(-) (limited to 'src/Module.zig') diff --git a/lib/std/crypto/aes/soft.zig b/lib/std/crypto/aes/soft.zig index b57f1746dc..d8bd3d4ac0 100644 --- a/lib/std/crypto/aes/soft.zig +++ b/lib/std/crypto/aes/soft.zig @@ -420,7 +420,7 @@ const powx = init: { var array: [16]u8 = undefined; var value = 1; - for (array) |*power| { + for (&array) |*power| { power.* = value; value = mul(value, 2); } diff --git a/src/Module.zig b/src/Module.zig index 377ccd2441..76777532ab 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -2469,6 +2469,48 @@ pub const SrcLoc = struct { const src_node = for_full.ast.inputs[for_input.input_index]; return nodeToSpan(tree, src_node); }, + .for_capture_from_input => |node_off| { + const tree = try src_loc.file_scope.getTree(gpa); + const token_tags = tree.tokens.items(.tag); + const input_node = src_loc.declRelativeToNodeIndex(node_off); + // We have to actually linear scan the whole AST to find the for loop + // that contains this input. + const node_tags = tree.nodes.items(.tag); + for (node_tags, 0..) |node_tag, node_usize| { + const node = @intCast(Ast.Node.Index, node_usize); + switch (node_tag) { + .for_simple, .@"for" => { + const for_full = tree.fullFor(node).?; + for (for_full.ast.inputs, 0..) |input, input_index| { + if (input_node == input) { + var count = input_index; + var tok = for_full.payload_token; + while (true) { + switch (token_tags[tok]) { + .comma => { + count -= 1; + tok += 1; + }, + .identifier => { + if (count == 0) + return tokensToSpan(tree, tok, tok + 1, tok); + tok += 1; + }, + .asterisk => { + if (count == 0) + return tokensToSpan(tree, tok, tok + 2, tok); + tok += 1; + }, + else => unreachable, + } + } + } + } + }, + else => continue, + } + } else unreachable; + }, .node_offset_bin_lhs => |node_off| { const tree = try src_loc.file_scope.getTree(gpa); const node = src_loc.declRelativeToNodeIndex(node_off); @@ -3129,6 +3171,12 @@ pub const LazySrcLoc = union(enum) { /// Picks one of the inputs from the condition. input_index: u32, }, + /// The source location points to one of the captures of a for loop, found + /// by taking this AST node index offset from the containing + /// Decl AST node, which points to one of the input nodes of a for loop. + /// Next, navigate to the corresponding capture. + /// The Decl is determined contextually. + for_capture_from_input: i32, pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease; @@ -3216,6 +3264,7 @@ pub const LazySrcLoc = union(enum) { .node_offset_store_ptr, .node_offset_store_operand, .for_input, + .for_capture_from_input, => .{ .file_scope = decl.getFileScope(), .parent_decl_node = decl.src_node, diff --git a/src/Sema.zig b/src/Sema.zig index 7e8520eaa1..07176ad1a0 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -9716,6 +9716,21 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const array_ptr = try sema.resolveInst(extra.lhs); const elem_index = try sema.resolveInst(extra.rhs); + const indexable_ty = sema.typeOf(array_ptr); + if (indexable_ty.zigTypeTag() != .Pointer) { + const capture_src: LazySrcLoc = .{ .for_capture_from_input = inst_data.src_node }; + const msg = msg: { + const msg = try sema.errMsg(block, capture_src, "pointer capture of non pointer type '{}'", .{ + indexable_ty.fmt(sema.mod), + }); + errdefer msg.destroy(sema.gpa); + if (indexable_ty.zigTypeTag() == .Array) { + try sema.errNote(block, src, msg, "consider using '&' here", .{}); + } + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); + } return sema.elemPtrOneLayerOnly(block, src, array_ptr, elem_index, src, false); } @@ -24195,12 +24210,7 @@ fn elemPtrOneLayerOnly( }, } }, - else => { - // TODO add note pointing at corresponding for loop input and suggest using '&' - return sema.fail(block, indexable_src, "pointer capture of non pointer type '{}'", .{ - indexable_ty.fmt(sema.mod), - }); - }, + else => unreachable, } } diff --git a/test/cases/compile_errors/for.zig b/test/cases/compile_errors/for.zig index abb87084b4..dff46af085 100644 --- a/test/cases/compile_errors/for.zig +++ b/test/cases/compile_errors/for.zig @@ -10,6 +10,12 @@ export fn b() void { _ = i; _ = j; } } +export fn c() void { + var buf: [10]u8 = undefined; + for (buf) |*byte| { + _ = byte; + } +} // error // backend=stage2 @@ -20,3 +26,5 @@ export fn b() void { // :2:19: note: length 11 here // :9:14: error: type 'bool' does not support indexing // :9:14: note: for loop operand must be an array, slice, tuple, or vector +// :15:16: error: pointer capture of non pointer type '[10]u8' +// :15:10: note: consider using '&' here -- cgit v1.2.3