diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-03-07 13:54:09 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-03-07 13:54:09 -0500 |
| commit | f59cbd89e349fb3002500cb2a1d69ca5e6063338 (patch) | |
| tree | fd60d586a95f7d23cce8ee671e36eee7a14ede68 | |
| parent | 8c32d989c995f8675f1824fb084245b833b26223 (diff) | |
| parent | 85b0a4a8fd8a56c07e0377b02d33753fe205fe41 (diff) | |
| download | zig-f59cbd89e349fb3002500cb2a1d69ca5e6063338.tar.gz zig-f59cbd89e349fb3002500cb2a1d69ca5e6063338.zip | |
Merge pull request #11077 from mitchellh/array-init-ty
stage2: sentinel-terminated array initialization
| -rw-r--r-- | src/AstGen.zig | 47 | ||||
| -rw-r--r-- | src/Sema.zig | 41 | ||||
| -rw-r--r-- | src/Zir.zig | 12 | ||||
| -rw-r--r-- | src/print_zir.zig | 24 | ||||
| -rw-r--r-- | test/behavior/pointers.zig | 8 |
5 files changed, 113 insertions, 19 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index fdd58dd948..d3ef670723 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, .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, .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, .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, .array_init); + return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, elem_type, types.sentinel, false); } }, .ptr => |ptr_inst| { @@ -1387,14 +1392,32 @@ fn arrayInitExprRlTy( node: Ast.Node.Index, elements: []const Ast.Node.Index, elem_ty_inst: 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), + .operands_len = @intCast(u32, info.len), }); - var extra_index = try reserveExtra(astgen, elements.len); + var extra_index = try reserveExtra(astgen, info.len); const elem_rl: ResultLoc = .{ .ty = elem_ty_inst }; for (elements) |elem_init| { @@ -1402,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( @@ -2217,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 4da7fabac6..5be0ef364f 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; @@ -11797,22 +11800,38 @@ fn zirArrayInit( for (args) |arg, i| resolved_args[i] = sema.resolveInst(arg); 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, + }); + } - const array_ty = try Type.Tag.array.create(sema.arena, .{ - .len = resolved_args.len, - .elem_type = elem_ty, - }); + 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 = if (!is_sent) + resolved_args + else + resolved_args[0 .. resolved_args.len - 1]; - const opt_runtime_src: ?LazySrcLoc = for (resolved_args) |arg| { + const opt_runtime_src: ?LazySrcLoc = for (elems) |arg| { const arg_src = src; // TODO better source location const comptime_known = try sema.isComptimeKnown(block, arg_src, arg); if (!comptime_known) break arg_src; } else null; const runtime_src = opt_runtime_src orelse { - const elem_vals = try sema.arena.alloc(Value, resolved_args.len); + const elem_vals = try sema.arena.alloc(Value, elems.len); - for (resolved_args) |arg, i| { + for (elems) |arg, i| { // We checked that all args are comptime above. elem_vals[i] = (sema.resolveMaybeUndefVal(block, src, arg) catch unreachable).?; } @@ -11839,7 +11858,7 @@ fn zirArrayInit( }); const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty); - for (resolved_args) |arg, i| { + for (elems) |arg, i| { const index = try sema.addIntUnsigned(Type.usize, i); const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref); _ = try block.addBinOp(.store, elem_ptr, arg); @@ -11847,7 +11866,7 @@ fn zirArrayInit( return alloc; } - return block.addAggregateInit(array_ty, resolved_args); + return block.addAggregateInit(array_ty, elems); } fn zirArrayInitAnon( diff --git a/src/Zir.zig b/src/Zir.zig index 5ccdbda86d..ceaef3ebe0 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, @@ -1121,8 +1129,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, @@ -1379,8 +1389,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"; diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index 6fd7e41a6d..d2ec6d9bbc 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -270,6 +270,14 @@ test "assign null directly to C pointer and test null equality" { comptime try expect((y1 orelse &othery) == y1); } +test "array initialization types" { + const E = enum { A, B, C }; + try expect(@TypeOf([_]u8{}) == [0]u8); + try expect(@TypeOf([_:0]u8{}) == [0:0]u8); + try expect(@TypeOf([_:.A]E{}) == [0:.A]E); + try expect(@TypeOf([_:0]u8{ 1, 2, 3 }) == [3:0]u8); +} + test "null terminated pointer" { if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO |
