diff options
| author | mlugg <mlugg@mlugg.co.uk> | 2025-01-03 07:54:53 +0000 |
|---|---|---|
| committer | Matthew Lugg <mlugg@mlugg.co.uk> | 2025-01-03 22:28:37 +0000 |
| commit | b4da8eef2a393543e9520c544364689ab482b080 (patch) | |
| tree | 3c21ba65a2bcb5eb3d970868d6d8b08e3757a073 /src | |
| parent | 252c2031011f80b35d01d5ba5a2a2577c870f90c (diff) | |
| download | zig-b4da8eef2a393543e9520c544364689ab482b080.tar.gz zig-b4da8eef2a393543e9520c544364689ab482b080.zip | |
Zir: split up start and end of range in `for_len`
The old lowering was kind of neat, but it unintentionally allowed the
syntax `for (123) |_| { ... }`, and there wasn't really a way to fix
that. So, instead, we include both the start and the end of the range in
the `for_len` instruction (each operand to `for` now has *two* entries
in this multi-op instruction). This slightly increases the size of ZIR
for loops of predominantly indexables, but the difference is small
enough that it's not worth complicating ZIR to try and fix it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/Sema.zig | 43 |
1 files changed, 20 insertions, 23 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index 4b79274ee5..0ec1a24939 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -4356,7 +4356,8 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. const ip = &zcu.intern_pool; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); - const args = sema.code.refSlice(extra.end, extra.data.operands_len); + const all_args = sema.code.refSlice(extra.end, extra.data.operands_len); + const arg_pairs: []const [2]Zir.Inst.Ref = @as([*]const [2]Zir.Inst.Ref, @ptrCast(all_args))[0..@divExact(all_args.len, 2)]; const src = block.nodeOffset(inst_data.src_node); var len: Air.Inst.Ref = .none; @@ -4364,27 +4365,24 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. var len_idx: u32 = undefined; var any_runtime = false; - const runtime_arg_lens = try gpa.alloc(Air.Inst.Ref, args.len); + const runtime_arg_lens = try gpa.alloc(Air.Inst.Ref, arg_pairs.len); defer gpa.free(runtime_arg_lens); // First pass to look for comptime values. - for (args, 0..) |zir_arg, i_usize| { + for (arg_pairs, 0..) |zir_arg_pair, i_usize| { const i: u32 = @intCast(i_usize); runtime_arg_lens[i] = .none; - if (zir_arg == .none) continue; - const object = try sema.resolveInst(zir_arg); - const object_ty = sema.typeOf(object); - // Each arg could be an indexable, or a range, in which case the length - // is passed directly as an integer. - const is_int = switch (object_ty.zigTypeTag(zcu)) { - .int, .comptime_int => true, - else => false, - }; + if (zir_arg_pair[0] == .none) continue; + const arg_src = block.src(.{ .for_input = .{ .for_node_offset = inst_data.src_node, .input_index = i, } }); - const arg_len_uncoerced = if (is_int) object else l: { + + const arg_len_uncoerced = if (zir_arg_pair[1] == .none) l: { + // This argument is an indexable. + const object = try sema.resolveInst(zir_arg_pair[0]); + const object_ty = sema.typeOf(object); if (!object_ty.isIndexable(zcu)) { // Instead of using checkIndexable we customize this error. const msg = msg: { @@ -4401,8 +4399,12 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. return sema.failWithOwnedErrorMsg(block, msg); } if (!object_ty.indexableHasLen(zcu)) continue; - break :l try sema.fieldVal(block, arg_src, object, try ip.getOrPutString(gpa, pt.tid, "len", .no_embedded_nulls), arg_src); + } else l: { + // This argument is a range. + const range_start = try sema.resolveInst(zir_arg_pair[0]); + const range_end = try sema.resolveInst(zir_arg_pair[1]); + break :l try sema.analyzeArithmetic(block, .sub, range_end, range_start, arg_src, arg_src, arg_src, true); }; const arg_len = try sema.coerce(block, Type.usize, arg_len_uncoerced, arg_src); if (len == .none) { @@ -4444,17 +4446,12 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. const msg = msg: { const msg = try sema.errMsg(src, "unbounded for loop", .{}); errdefer msg.destroy(gpa); - for (args, 0..) |zir_arg, i_usize| { + for (arg_pairs, 0..) |zir_arg_pair, i_usize| { const i: u32 = @intCast(i_usize); - if (zir_arg == .none) continue; - const object = try sema.resolveInst(zir_arg); + if (zir_arg_pair[0] == .none) continue; + if (zir_arg_pair[1] != .none) continue; + const object = try sema.resolveInst(zir_arg_pair[0]); const object_ty = sema.typeOf(object); - // Each arg could be an indexable, or a range, in which case the length - // is passed directly as an integer. - switch (object_ty.zigTypeTag(zcu)) { - .int, .comptime_int => continue, - else => {}, - } const arg_src = block.src(.{ .for_input = .{ .for_node_offset = inst_data.src_node, .input_index = i, |
