diff options
| author | Mitchell Hashimoto <mitchell.hashimoto@gmail.com> | 2022-03-07 08:26:00 -0800 |
|---|---|---|
| committer | Mitchell Hashimoto <mitchell.hashimoto@gmail.com> | 2022-03-07 08:26:00 -0800 |
| commit | 85b0a4a8fd8a56c07e0377b02d33753fe205fe41 (patch) | |
| tree | 175a059ce3b60e6da72cc1e3c70b37d0af54a216 /src | |
| parent | c9fac41368c872d424681ea3cf93a9d97157143e (diff) | |
| download | zig-85b0a4a8fd8a56c07e0377b02d33753fe205fe41.tar.gz zig-85b0a4a8fd8a56c07e0377b02d33753fe205fe41.zip | |
stage2: new zir array_init_sent for sentinel-terminated array inits
This uses a new ZIR inst `array_init_sent` (and a ref equivalent) to
represent array init expressions that terminate in a a sentinel value.
The sentienl value is the last value in the `MultiOp` payload. This
makes it a bit more awkward to deal with (lots of "len - 1") but makes
it so that the payload matches the fact that sentinels appear at the end
of arrays. However, this is not a hill I want to die on so if we want to
change it to index 0, I'm happy to do so.
This makes the following work properly:
try expect(@TypeOf([_:0]u8{}) == [0:0]u8);
Diffstat (limited to 'src')
| -rw-r--r-- | src/AstGen.zig | 51 | ||||
| -rw-r--r-- | src/Sema.zig | 40 | ||||
| -rw-r--r-- | src/Zir.zig | 12 | ||||
| -rw-r--r-- | src/print_zir.zig | 24 |
4 files changed, 99 insertions, 28 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index 8197589523..37a12c8b13 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -1259,10 +1259,12 @@ fn arrayInitExpr( const types: struct { array: Zir.Inst.Ref, elem: Zir.Inst.Ref, + sentinel: Zir.Inst.Ref, } = inst: { if (array_init.ast.type_expr == 0) break :inst .{ .array = .none, .elem = .none, + .sentinel = .none, }; infer: { @@ -1282,6 +1284,7 @@ fn arrayInitExpr( break :inst .{ .array = array_type_inst, .elem = elem_type, + .sentinel = .none, }; } else { const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel); @@ -1297,6 +1300,7 @@ fn arrayInitExpr( break :inst .{ .array = array_type_inst, .elem = elem_type, + .sentinel = sentinel, }; } } @@ -1307,6 +1311,7 @@ fn arrayInitExpr( break :inst .{ .array = array_type_inst, .elem = elem_type, + .sentinel = .none, }; }; @@ -1319,25 +1324,25 @@ fn arrayInitExpr( }, .ref => { if (types.array != .none) { - return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.array, .array_init_ref); + return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, true); } else { return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref); } }, .none => { if (types.array != .none) { - return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.array, .array_init); + return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, false); } else { return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); } }, .ty, .coerced_ty => |ty_inst| { if (types.array != .none) { - const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.array, .array_init); + const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, false); return rvalue(gz, rl, result, node); } else { const elem_type = try gz.addUnNode(.elem_type, ty_inst, node); - return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, elem_type, types.array, .array_init); + return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, elem_type, types.sentinel, false); } }, .ptr => |ptr_inst| { @@ -1387,18 +1392,32 @@ fn arrayInitExprRlTy( node: Ast.Node.Index, elements: []const Ast.Node.Index, elem_ty_inst: Zir.Inst.Ref, - array_ty: Zir.Inst.Ref, - tag: Zir.Inst.Tag, + sentinel: Zir.Inst.Ref, + ref: bool, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; + const info: struct { + len: usize, + tag: Zir.Inst.Tag, + } = blk: { + if (sentinel != .none) { + break :blk .{ + .len = elements.len + 1, + .tag = if (ref) .array_init_sent_ref else .array_init_sent, + }; + } else { + break :blk .{ + .len = elements.len, + .tag = if (ref) .array_init_ref else .array_init, + }; + } + }; + const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{ - .operands_len = @intCast(u32, elements.len + 1), + .operands_len = @intCast(u32, info.len), }); - var extra_index = try reserveExtra(astgen, elements.len + 1); - - astgen.extra.items[extra_index] = @enumToInt(array_ty); - extra_index += 1; + var extra_index = try reserveExtra(astgen, info.len); const elem_rl: ResultLoc = .{ .ty = elem_ty_inst }; for (elements) |elem_init| { @@ -1406,7 +1425,13 @@ fn arrayInitExprRlTy( astgen.extra.items[extra_index] = @enumToInt(elem_ref); extra_index += 1; } - return try gz.addPlNodePayloadIndex(tag, node, payload_index); + + if (sentinel != .none) { + astgen.extra.items[extra_index] = @enumToInt(sentinel); + extra_index += 1; + } + + return try gz.addPlNodePayloadIndex(info.tag, node, payload_index); } fn arrayInitExprRlPtr( @@ -2221,8 +2246,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner .struct_init_anon_ref, .array_init, .array_init_anon, + .array_init_sent, .array_init_ref, .array_init_anon_ref, + .array_init_sent_ref, .union_init, .field_type, .field_type_ref, diff --git a/src/Sema.zig b/src/Sema.zig index 6c1c3d57b0..4015917e51 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -712,8 +712,10 @@ fn analyzeBodyInner( .struct_init_ref => try sema.zirStructInit(block, inst, true), .struct_init_anon => try sema.zirStructInitAnon(block, inst, false), .struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true), - .array_init => try sema.zirArrayInit(block, inst, false), - .array_init_ref => try sema.zirArrayInit(block, inst, true), + .array_init => try sema.zirArrayInit(block, inst, false, false), + .array_init_sent => try sema.zirArrayInit(block, inst, false, true), + .array_init_ref => try sema.zirArrayInit(block, inst, true, false), + .array_init_sent_ref => try sema.zirArrayInit(block, inst, true, true), .array_init_anon => try sema.zirArrayInitAnon(block, inst, false), .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true), .union_init => try sema.zirUnionInit(block, inst), @@ -11782,6 +11784,7 @@ fn zirArrayInit( block: *Block, inst: Zir.Inst.Index, is_ref: bool, + is_sent: bool, ) CompileError!Air.Inst.Ref { const gpa = sema.gpa; const inst_data = sema.code.instructions.items(.data)[inst].pl_node; @@ -11796,23 +11799,28 @@ fn zirArrayInit( for (args) |arg, i| resolved_args[i] = sema.resolveInst(arg); - const elem_ty = sema.typeOf(resolved_args[1]); - const array_ty = switch (resolved_args[0]) { - .none => try Type.Tag.array.create(sema.arena, .{ - .len = resolved_args.len, - .elem_type = elem_ty, - }), + const elem_ty = sema.typeOf(resolved_args[0]); + const array_ty = blk: { + if (!is_sent) { + break :blk try Type.Tag.array.create(sema.arena, .{ + .len = resolved_args.len, + .elem_type = elem_ty, + }); + } - else => |ref| blk: { - assert(sema.typeOf(ref).zigTypeTag() == .Type); - var buffer: Value.ToTypeBuffer = undefined; - const val = try sema.resolveConstValue(block, src, ref); - const ty = val.toType(&buffer); - break :blk try ty.copy(sema.arena); - }, + const sentinel_ref = resolved_args[resolved_args.len - 1]; + const val = try sema.resolveConstValue(block, src, sentinel_ref); + break :blk try Type.Tag.array_sentinel.create(sema.arena, .{ + .len = resolved_args.len - 1, + .sentinel = val, + .elem_type = elem_ty, + }); }; - const elems = resolved_args[1..]; + const elems = if (!is_sent) + resolved_args + else + resolved_args[0 .. resolved_args.len - 1]; const opt_runtime_src: ?LazySrcLoc = for (elems) |arg| { const arg_src = src; // TODO better source location diff --git a/src/Zir.zig b/src/Zir.zig index caf2002f0f..07974964e2 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -710,12 +710,20 @@ pub const Inst = struct { /// Array initialization syntax. /// Uses the `pl_node` field. Payload is `MultiOp`. array_init, + /// Array initialization with sentinel. + /// Uses the `pl_node` field. Payload is `MultiOp`. + /// Final op in MultiOp is the sentinel. + array_init_sent, /// Anonymous array initialization syntax. /// Uses the `pl_node` field. Payload is `MultiOp`. array_init_anon, /// Array initialization syntax, make the result a pointer. /// Uses the `pl_node` field. Payload is `MultiOp`. array_init_ref, + /// Array initialization with sentinel. + /// Uses the `pl_node` field. Payload is `MultiOp`. + /// Final op in MultiOp is the sentinel. + array_init_sent_ref, /// Anonymous array initialization syntax, make the result a pointer. /// Uses the `pl_node` field. Payload is `MultiOp`. array_init_anon_ref, @@ -1119,8 +1127,10 @@ pub const Inst = struct { .struct_init_anon, .struct_init_anon_ref, .array_init, + .array_init_sent, .array_init_anon, .array_init_ref, + .array_init_sent_ref, .array_init_anon_ref, .union_init, .field_type, @@ -1377,8 +1387,10 @@ pub const Inst = struct { .struct_init_anon = .pl_node, .struct_init_anon_ref = .pl_node, .array_init = .pl_node, + .array_init_sent = .pl_node, .array_init_anon = .pl_node, .array_init_ref = .pl_node, + .array_init_sent_ref = .pl_node, .array_init_anon_ref = .pl_node, .union_init = .pl_node, .type_info = .un_node, diff --git a/src/print_zir.zig b/src/print_zir.zig index 36b821f386..677248abd3 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -269,6 +269,10 @@ const Writer = struct { .array_init_anon_ref, => try self.writeArrayInit(stream, inst), + .array_init_sent, + .array_init_sent_ref, + => try self.writeArrayInitSent(stream, inst), + .slice_start => try self.writeSliceStart(stream, inst), .slice_end => try self.writeSliceEnd(stream, inst), .slice_sentinel => try self.writeSliceSentinel(stream, inst), @@ -2022,6 +2026,26 @@ const Writer = struct { try self.writeSrc(stream, inst_data.src()); } + fn writeArrayInitSent(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + + const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); + const args = self.code.refSlice(extra.end, extra.data.operands_len); + const sent = args[args.len - 1]; + const elems = args[0 .. args.len - 1]; + + try self.writeInstRef(stream, sent); + try stream.writeAll(", "); + + try stream.writeAll(".{"); + for (elems) |elem, i| { + if (i != 0) try stream.writeAll(", "); + try self.writeInstRef(stream, elem); + } + try stream.writeAll("}) "); + try self.writeSrc(stream, inst_data.src()); + } + fn writeUnreachable(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[inst].@"unreachable"; const safety_str = if (inst_data.safety) "safe" else "unsafe"; |
