authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-07 13:54:09-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-07 13:54:09-05:00
logf59cbd89e349fb3002500cb2a1d69ca5e6063338
treefd60d586a95f7d23cce8ee671e36eee7a14ede68
parent8c32d989c995f8675f1824fb084245b833b26223
parent85b0a4a8fd8a56c07e0377b02d33753fe205fe41
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11077 from mitchellh/array-init-ty

stage2: sentinel-terminated array initialization

5 files changed, 113 insertions(+), 19 deletions(-)

src/AstGen.zig+39-8
...@@ -1259,10 +1259,12 @@ fn arrayInitExpr(...@@ -1259,10 +1259,12 @@ fn arrayInitExpr(
1259 const types: struct {1259 const types: struct {
1260 array: Zir.Inst.Ref,1260 array: Zir.Inst.Ref,
1261 elem: Zir.Inst.Ref,1261 elem: Zir.Inst.Ref,
1262 sentinel: Zir.Inst.Ref,
1262 } = inst: {1263 } = inst: {
1263 if (array_init.ast.type_expr == 0) break :inst .{1264 if (array_init.ast.type_expr == 0) break :inst .{
1264 .array = .none,1265 .array = .none,
1265 .elem = .none,1266 .elem = .none,
1267 .sentinel = .none,
1266 };1268 };
12671269
1268 infer: {1270 infer: {
...@@ -1282,6 +1284,7 @@ fn arrayInitExpr(...@@ -1282,6 +1284,7 @@ fn arrayInitExpr(
1282 break :inst .{1284 break :inst .{
1283 .array = array_type_inst,1285 .array = array_type_inst,
1284 .elem = elem_type,1286 .elem = elem_type,
1287 .sentinel = .none,
1285 };1288 };
1286 } else {1289 } else {
1287 const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel);1290 const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel);
...@@ -1297,6 +1300,7 @@ fn arrayInitExpr(...@@ -1297,6 +1300,7 @@ fn arrayInitExpr(
1297 break :inst .{1300 break :inst .{
1298 .array = array_type_inst,1301 .array = array_type_inst,
1299 .elem = elem_type,1302 .elem = elem_type,
1303 .sentinel = sentinel,
1300 };1304 };
1301 }1305 }
1302 }1306 }
...@@ -1307,6 +1311,7 @@ fn arrayInitExpr(...@@ -1307,6 +1311,7 @@ fn arrayInitExpr(
1307 break :inst .{1311 break :inst .{
1308 .array = array_type_inst,1312 .array = array_type_inst,
1309 .elem = elem_type,1313 .elem = elem_type,
1314 .sentinel = .none,
1310 };1315 };
1311 };1316 };
13121317
...@@ -1319,25 +1324,25 @@ fn arrayInitExpr(...@@ -1319,25 +1324,25 @@ fn arrayInitExpr(
1319 },1324 },
1320 .ref => {1325 .ref => {
1321 if (types.array != .none) {1326 if (types.array != .none) {
1322 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init_ref);1327 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, true);
1323 } else {1328 } else {
1324 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref);1329 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref);
1325 }1330 }
1326 },1331 },
1327 .none => {1332 .none => {
1328 if (types.array != .none) {1333 if (types.array != .none) {
1329 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init);1334 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, false);
1330 } else {1335 } else {
1331 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);1336 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
1332 }1337 }
1333 },1338 },
1334 .ty, .coerced_ty => |ty_inst| {1339 .ty, .coerced_ty => |ty_inst| {
1335 if (types.array != .none) {1340 if (types.array != .none) {
1336 const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init);1341 const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, false);
1337 return rvalue(gz, rl, result, node);1342 return rvalue(gz, rl, result, node);
1338 } else {1343 } else {
1339 const elem_type = try gz.addUnNode(.elem_type, ty_inst, node);1344 const elem_type = try gz.addUnNode(.elem_type, ty_inst, node);
1340 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, elem_type, .array_init);1345 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, elem_type, types.sentinel, false);
1341 }1346 }
1342 },1347 },
1343 .ptr => |ptr_inst| {1348 .ptr => |ptr_inst| {
...@@ -1387,14 +1392,32 @@ fn arrayInitExprRlTy(...@@ -1387,14 +1392,32 @@ fn arrayInitExprRlTy(
1387 node: Ast.Node.Index,1392 node: Ast.Node.Index,
1388 elements: []const Ast.Node.Index,1393 elements: []const Ast.Node.Index,
1389 elem_ty_inst: Zir.Inst.Ref,1394 elem_ty_inst: Zir.Inst.Ref,
1390 tag: Zir.Inst.Tag,1395 sentinel: Zir.Inst.Ref,
1396 ref: bool,
1391) InnerError!Zir.Inst.Ref {1397) InnerError!Zir.Inst.Ref {
1392 const astgen = gz.astgen;1398 const astgen = gz.astgen;
13931399
1400 const info: struct {
1401 len: usize,
1402 tag: Zir.Inst.Tag,
1403 } = blk: {
1404 if (sentinel != .none) {
1405 break :blk .{
1406 .len = elements.len + 1,
1407 .tag = if (ref) .array_init_sent_ref else .array_init_sent,
1408 };
1409 } else {
1410 break :blk .{
1411 .len = elements.len,
1412 .tag = if (ref) .array_init_ref else .array_init,
1413 };
1414 }
1415 };
1416
1394 const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{1417 const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{
1395 .operands_len = @intCast(u32, elements.len),1418 .operands_len = @intCast(u32, info.len),
1396 });1419 });
1397 var extra_index = try reserveExtra(astgen, elements.len);1420 var extra_index = try reserveExtra(astgen, info.len);
13981421
1399 const elem_rl: ResultLoc = .{ .ty = elem_ty_inst };1422 const elem_rl: ResultLoc = .{ .ty = elem_ty_inst };
1400 for (elements) |elem_init| {1423 for (elements) |elem_init| {
...@@ -1402,7 +1425,13 @@ fn arrayInitExprRlTy(...@@ -1402,7 +1425,13 @@ fn arrayInitExprRlTy(
1402 astgen.extra.items[extra_index] = @enumToInt(elem_ref);1425 astgen.extra.items[extra_index] = @enumToInt(elem_ref);
1403 extra_index += 1;1426 extra_index += 1;
1404 }1427 }
1405 return try gz.addPlNodePayloadIndex(tag, node, payload_index);1428
1429 if (sentinel != .none) {
1430 astgen.extra.items[extra_index] = @enumToInt(sentinel);
1431 extra_index += 1;
1432 }
1433
1434 return try gz.addPlNodePayloadIndex(info.tag, node, payload_index);
1406}1435}
14071436
1408fn arrayInitExprRlPtr(1437fn arrayInitExprRlPtr(
...@@ -2217,8 +2246,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner...@@ -2217,8 +2246,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
2217 .struct_init_anon_ref,2246 .struct_init_anon_ref,
2218 .array_init,2247 .array_init,
2219 .array_init_anon,2248 .array_init_anon,
2249 .array_init_sent,
2220 .array_init_ref,2250 .array_init_ref,
2221 .array_init_anon_ref,2251 .array_init_anon_ref,
2252 .array_init_sent_ref,
2222 .union_init,2253 .union_init,
2223 .field_type,2254 .field_type,
2224 .field_type_ref,2255 .field_type_ref,
src/Sema.zig+30-11
...@@ -712,8 +712,10 @@ fn analyzeBodyInner(...@@ -712,8 +712,10 @@ fn analyzeBodyInner(
712 .struct_init_ref => try sema.zirStructInit(block, inst, true),712 .struct_init_ref => try sema.zirStructInit(block, inst, true),
713 .struct_init_anon => try sema.zirStructInitAnon(block, inst, false),713 .struct_init_anon => try sema.zirStructInitAnon(block, inst, false),
714 .struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true),714 .struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true),
715 .array_init => try sema.zirArrayInit(block, inst, false),715 .array_init => try sema.zirArrayInit(block, inst, false, false),
716 .array_init_ref => try sema.zirArrayInit(block, inst, true),716 .array_init_sent => try sema.zirArrayInit(block, inst, false, true),
717 .array_init_ref => try sema.zirArrayInit(block, inst, true, false),
718 .array_init_sent_ref => try sema.zirArrayInit(block, inst, true, true),
717 .array_init_anon => try sema.zirArrayInitAnon(block, inst, false),719 .array_init_anon => try sema.zirArrayInitAnon(block, inst, false),
718 .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true),720 .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true),
719 .union_init => try sema.zirUnionInit(block, inst),721 .union_init => try sema.zirUnionInit(block, inst),
...@@ -11782,6 +11784,7 @@ fn zirArrayInit(...@@ -11782,6 +11784,7 @@ fn zirArrayInit(
11782 block: *Block,11784 block: *Block,
11783 inst: Zir.Inst.Index,11785 inst: Zir.Inst.Index,
11784 is_ref: bool,11786 is_ref: bool,
11787 is_sent: bool,
11785) CompileError!Air.Inst.Ref {11788) CompileError!Air.Inst.Ref {
11786 const gpa = sema.gpa;11789 const gpa = sema.gpa;
11787 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;11790 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
...@@ -11797,22 +11800,38 @@ fn zirArrayInit(...@@ -11797,22 +11800,38 @@ fn zirArrayInit(
11797 for (args) |arg, i| resolved_args[i] = sema.resolveInst(arg);11800 for (args) |arg, i| resolved_args[i] = sema.resolveInst(arg);
1179811801
11799 const elem_ty = sema.typeOf(resolved_args[0]);11802 const elem_ty = sema.typeOf(resolved_args[0]);
11803 const array_ty = blk: {
11804 if (!is_sent) {
11805 break :blk try Type.Tag.array.create(sema.arena, .{
11806 .len = resolved_args.len,
11807 .elem_type = elem_ty,
11808 });
11809 }
1180011810
11801 const array_ty = try Type.Tag.array.create(sema.arena, .{11811 const sentinel_ref = resolved_args[resolved_args.len - 1];
11802 .len = resolved_args.len,11812 const val = try sema.resolveConstValue(block, src, sentinel_ref);
11803 .elem_type = elem_ty,11813 break :blk try Type.Tag.array_sentinel.create(sema.arena, .{
11804 });11814 .len = resolved_args.len - 1,
11815 .sentinel = val,
11816 .elem_type = elem_ty,
11817 });
11818 };
11819
11820 const elems = if (!is_sent)
11821 resolved_args
11822 else
11823 resolved_args[0 .. resolved_args.len - 1];
1180511824
11806 const opt_runtime_src: ?LazySrcLoc = for (resolved_args) |arg| {11825 const opt_runtime_src: ?LazySrcLoc = for (elems) |arg| {
11807 const arg_src = src; // TODO better source location11826 const arg_src = src; // TODO better source location
11808 const comptime_known = try sema.isComptimeKnown(block, arg_src, arg);11827 const comptime_known = try sema.isComptimeKnown(block, arg_src, arg);
11809 if (!comptime_known) break arg_src;11828 if (!comptime_known) break arg_src;
11810 } else null;11829 } else null;
1181111830
11812 const runtime_src = opt_runtime_src orelse {11831 const runtime_src = opt_runtime_src orelse {
11813 const elem_vals = try sema.arena.alloc(Value, resolved_args.len);11832 const elem_vals = try sema.arena.alloc(Value, elems.len);
1181411833
11815 for (resolved_args) |arg, i| {11834 for (elems) |arg, i| {
11816 // We checked that all args are comptime above.11835 // We checked that all args are comptime above.
11817 elem_vals[i] = (sema.resolveMaybeUndefVal(block, src, arg) catch unreachable).?;11836 elem_vals[i] = (sema.resolveMaybeUndefVal(block, src, arg) catch unreachable).?;
11818 }11837 }
...@@ -11839,7 +11858,7 @@ fn zirArrayInit(...@@ -11839,7 +11858,7 @@ fn zirArrayInit(
11839 });11858 });
11840 const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty);11859 const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty);
1184111860
11842 for (resolved_args) |arg, i| {11861 for (elems) |arg, i| {
11843 const index = try sema.addIntUnsigned(Type.usize, i);11862 const index = try sema.addIntUnsigned(Type.usize, i);
11844 const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref);11863 const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref);
11845 _ = try block.addBinOp(.store, elem_ptr, arg);11864 _ = try block.addBinOp(.store, elem_ptr, arg);
...@@ -11847,7 +11866,7 @@ fn zirArrayInit(...@@ -11847,7 +11866,7 @@ fn zirArrayInit(
11847 return alloc;11866 return alloc;
11848 }11867 }
1184911868
11850 return block.addAggregateInit(array_ty, resolved_args);11869 return block.addAggregateInit(array_ty, elems);
11851}11870}
1185211871
11853fn zirArrayInitAnon(11872fn zirArrayInitAnon(
src/Zir.zig+12
...@@ -710,12 +710,20 @@ pub const Inst = struct {...@@ -710,12 +710,20 @@ pub const Inst = struct {
710 /// Array initialization syntax.710 /// Array initialization syntax.
711 /// Uses the `pl_node` field. Payload is `MultiOp`.711 /// Uses the `pl_node` field. Payload is `MultiOp`.
712 array_init,712 array_init,
713 /// Array initialization with sentinel.
714 /// Uses the `pl_node` field. Payload is `MultiOp`.
715 /// Final op in MultiOp is the sentinel.
716 array_init_sent,
713 /// Anonymous array initialization syntax.717 /// Anonymous array initialization syntax.
714 /// Uses the `pl_node` field. Payload is `MultiOp`.718 /// Uses the `pl_node` field. Payload is `MultiOp`.
715 array_init_anon,719 array_init_anon,
716 /// Array initialization syntax, make the result a pointer.720 /// Array initialization syntax, make the result a pointer.
717 /// Uses the `pl_node` field. Payload is `MultiOp`.721 /// Uses the `pl_node` field. Payload is `MultiOp`.
718 array_init_ref,722 array_init_ref,
723 /// Array initialization with sentinel.
724 /// Uses the `pl_node` field. Payload is `MultiOp`.
725 /// Final op in MultiOp is the sentinel.
726 array_init_sent_ref,
719 /// Anonymous array initialization syntax, make the result a pointer.727 /// Anonymous array initialization syntax, make the result a pointer.
720 /// Uses the `pl_node` field. Payload is `MultiOp`.728 /// Uses the `pl_node` field. Payload is `MultiOp`.
721 array_init_anon_ref,729 array_init_anon_ref,
...@@ -1121,8 +1129,10 @@ pub const Inst = struct {...@@ -1121,8 +1129,10 @@ pub const Inst = struct {
1121 .struct_init_anon,1129 .struct_init_anon,
1122 .struct_init_anon_ref,1130 .struct_init_anon_ref,
1123 .array_init,1131 .array_init,
1132 .array_init_sent,
1124 .array_init_anon,1133 .array_init_anon,
1125 .array_init_ref,1134 .array_init_ref,
1135 .array_init_sent_ref,
1126 .array_init_anon_ref,1136 .array_init_anon_ref,
1127 .union_init,1137 .union_init,
1128 .field_type,1138 .field_type,
...@@ -1379,8 +1389,10 @@ pub const Inst = struct {...@@ -1379,8 +1389,10 @@ pub const Inst = struct {
1379 .struct_init_anon = .pl_node,1389 .struct_init_anon = .pl_node,
1380 .struct_init_anon_ref = .pl_node,1390 .struct_init_anon_ref = .pl_node,
1381 .array_init = .pl_node,1391 .array_init = .pl_node,
1392 .array_init_sent = .pl_node,
1382 .array_init_anon = .pl_node,1393 .array_init_anon = .pl_node,
1383 .array_init_ref = .pl_node,1394 .array_init_ref = .pl_node,
1395 .array_init_sent_ref = .pl_node,
1384 .array_init_anon_ref = .pl_node,1396 .array_init_anon_ref = .pl_node,
1385 .union_init = .pl_node,1397 .union_init = .pl_node,
1386 .type_info = .un_node,1398 .type_info = .un_node,
src/print_zir.zig+24
...@@ -269,6 +269,10 @@ const Writer = struct {...@@ -269,6 +269,10 @@ const Writer = struct {
269 .array_init_anon_ref,269 .array_init_anon_ref,
270 => try self.writeArrayInit(stream, inst),270 => try self.writeArrayInit(stream, inst),
271271
272 .array_init_sent,
273 .array_init_sent_ref,
274 => try self.writeArrayInitSent(stream, inst),
275
272 .slice_start => try self.writeSliceStart(stream, inst),276 .slice_start => try self.writeSliceStart(stream, inst),
273 .slice_end => try self.writeSliceEnd(stream, inst),277 .slice_end => try self.writeSliceEnd(stream, inst),
274 .slice_sentinel => try self.writeSliceSentinel(stream, inst),278 .slice_sentinel => try self.writeSliceSentinel(stream, inst),
...@@ -2022,6 +2026,26 @@ const Writer = struct {...@@ -2022,6 +2026,26 @@ const Writer = struct {
2022 try self.writeSrc(stream, inst_data.src());2026 try self.writeSrc(stream, inst_data.src());
2023 }2027 }
20242028
2029 fn writeArrayInitSent(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2030 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2031
2032 const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
2033 const args = self.code.refSlice(extra.end, extra.data.operands_len);
2034 const sent = args[args.len - 1];
2035 const elems = args[0 .. args.len - 1];
2036
2037 try self.writeInstRef(stream, sent);
2038 try stream.writeAll(", ");
2039
2040 try stream.writeAll(".{");
2041 for (elems) |elem, i| {
2042 if (i != 0) try stream.writeAll(", ");
2043 try self.writeInstRef(stream, elem);
2044 }
2045 try stream.writeAll("}) ");
2046 try self.writeSrc(stream, inst_data.src());
2047 }
2048
2025 fn writeUnreachable(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {2049 fn writeUnreachable(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2026 const inst_data = self.code.instructions.items(.data)[inst].@"unreachable";2050 const inst_data = self.code.instructions.items(.data)[inst].@"unreachable";
2027 const safety_str = if (inst_data.safety) "safe" else "unsafe";2051 const safety_str = if (inst_data.safety) "safe" else "unsafe";
test/behavior/pointers.zig+8
...@@ -270,6 +270,14 @@ test "assign null directly to C pointer and test null equality" {...@@ -270,6 +270,14 @@ test "assign null directly to C pointer and test null equality" {
270 comptime try expect((y1 orelse &othery) == y1);270 comptime try expect((y1 orelse &othery) == y1);
271}271}
272272
273test "array initialization types" {
274 const E = enum { A, B, C };
275 try expect(@TypeOf([_]u8{}) == [0]u8);
276 try expect(@TypeOf([_:0]u8{}) == [0:0]u8);
277 try expect(@TypeOf([_:.A]E{}) == [0:.A]E);
278 try expect(@TypeOf([_:0]u8{ 1, 2, 3 }) == [3:0]u8);
279}
280
273test "null terminated pointer" {281test "null terminated pointer" {
274 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO282 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
275283