diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-02-19 10:10:59 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-19 10:10:59 -0500 |
| commit | 0bb178bbb2451238a326c6e916ecf38fbc34cab1 (patch) | |
| tree | b2499481c929ba1497d6eef8b85cc46205f953ab /src/Module.zig | |
| parent | 346ec15c5005e523c2a1d4b967ee7a4e5d1e9775 (diff) | |
| parent | 5fc6bbe71eeecb195d2cda2a2522e7fd04749d5b (diff) | |
| download | zig-0bb178bbb2451238a326c6e916ecf38fbc34cab1.tar.gz zig-0bb178bbb2451238a326c6e916ecf38fbc34cab1.zip | |
Merge pull request #14671 from ziglang/multi-object-for
implement multi-object for loops
Diffstat (limited to 'src/Module.zig')
| -rw-r--r-- | src/Module.zig | 79 |
1 files changed, 72 insertions, 7 deletions
diff --git a/src/Module.zig b/src/Module.zig index a129cb0cb6..76777532ab 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: { @@ -2462,6 +2462,55 @@ 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); + }, + .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); @@ -3114,6 +3163,20 @@ 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, + }, + /// 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; @@ -3200,6 +3263,8 @@ pub const LazySrcLoc = union(enum) { .node_offset_init_ty, .node_offset_store_ptr, .node_offset_store_operand, + .for_input, + .for_capture_from_input, => .{ .file_scope = decl.getFileScope(), .parent_decl_node = decl.src_node, @@ -3553,7 +3618,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 +3805,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 +6358,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: { |
