authorgravatar for mitchell.hashimoto@gmail.comMitchell Hashimoto <mitchell.hashimoto@gmail.com> 2022-03-07 08:26:00-08:00
committergravatar for mitchell.hashimoto@gmail.comMitchell Hashimoto <mitchell.hashimoto@gmail.com> 2022-03-07 08:26:00-08:00
log85b0a4a8fd8a56c07e0377b02d33753fe205fe41
tree175a059ce3b60e6da72cc1e3c70b37d0af54a216
parentc9fac41368c872d424681ea3cf93a9d97157143e
signaturelock-open Commit is signed but in an unrecognized format.

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);

4 files changed, 99 insertions(+), 28 deletions(-)

src/AstGen.zig+39-12
......@@ -1259,10 +1259,12 @@ fn arrayInitExpr(
12591259 const types: struct {
12601260 array: Zir.Inst.Ref,
12611261 elem: Zir.Inst.Ref,
1262 sentinel: Zir.Inst.Ref,
12621263 } = inst: {
12631264 if (array_init.ast.type_expr == 0) break :inst .{
12641265 .array = .none,
12651266 .elem = .none,
1267 .sentinel = .none,
12661268 };
12671269
12681270 infer: {
......@@ -1282,6 +1284,7 @@ fn arrayInitExpr(
12821284 break :inst .{
12831285 .array = array_type_inst,
12841286 .elem = elem_type,
1287 .sentinel = .none,
12851288 };
12861289 } else {
12871290 const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel);
......@@ -1297,6 +1300,7 @@ fn arrayInitExpr(
12971300 break :inst .{
12981301 .array = array_type_inst,
12991302 .elem = elem_type,
1303 .sentinel = sentinel,
13001304 };
13011305 }
13021306 }
......@@ -1307,6 +1311,7 @@ fn arrayInitExpr(
13071311 break :inst .{
13081312 .array = array_type_inst,
13091313 .elem = elem_type,
1314 .sentinel = .none,
13101315 };
13111316 };
13121317
......@@ -1319,25 +1324,25 @@ fn arrayInitExpr(
13191324 },
13201325 .ref => {
13211326 if (types.array != .none) {
1322 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.array, .array_init_ref);
1327 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, true);
13231328 } else {
13241329 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref);
13251330 }
13261331 },
13271332 .none => {
13281333 if (types.array != .none) {
1329 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.array, .array_init);
1334 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, false);
13301335 } else {
13311336 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
13321337 }
13331338 },
13341339 .ty, .coerced_ty => |ty_inst| {
13351340 if (types.array != .none) {
1336 const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.array, .array_init);
1341 const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, false);
13371342 return rvalue(gz, rl, result, node);
13381343 } else {
13391344 const elem_type = try gz.addUnNode(.elem_type, ty_inst, node);
1340 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, elem_type, types.array, .array_init);
1345 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, elem_type, types.sentinel, false);
13411346 }
13421347 },
13431348 .ptr => |ptr_inst| {
......@@ -1387,18 +1392,32 @@ fn arrayInitExprRlTy(
13871392 node: Ast.Node.Index,
13881393 elements: []const Ast.Node.Index,
13891394 elem_ty_inst: Zir.Inst.Ref,
1390 array_ty: Zir.Inst.Ref,
1391 tag: Zir.Inst.Tag,
1395 sentinel: Zir.Inst.Ref,
1396 ref: bool,
13921397) InnerError!Zir.Inst.Ref {
13931398 const astgen = gz.astgen;
13941399
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
13951417 const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{
1396 .operands_len = @intCast(u32, elements.len + 1),
1418 .operands_len = @intCast(u32, info.len),
13971419 });
1398 var extra_index = try reserveExtra(astgen, elements.len + 1);
1399
1400 astgen.extra.items[extra_index] = @enumToInt(array_ty);
1401 extra_index += 1;
1420 var extra_index = try reserveExtra(astgen, info.len);
14021421
14031422 const elem_rl: ResultLoc = .{ .ty = elem_ty_inst };
14041423 for (elements) |elem_init| {
......@@ -1406,7 +1425,13 @@ fn arrayInitExprRlTy(
14061425 astgen.extra.items[extra_index] = @enumToInt(elem_ref);
14071426 extra_index += 1;
14081427 }
1409 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);
14101435}
14111436
14121437fn arrayInitExprRlPtr(
......@@ -2221,8 +2246,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
22212246 .struct_init_anon_ref,
22222247 .array_init,
22232248 .array_init_anon,
2249 .array_init_sent,
22242250 .array_init_ref,
22252251 .array_init_anon_ref,
2252 .array_init_sent_ref,
22262253 .union_init,
22272254 .field_type,
22282255 .field_type_ref,
src/Sema.zig+24-16
......@@ -712,8 +712,10 @@ fn analyzeBodyInner(
712712 .struct_init_ref => try sema.zirStructInit(block, inst, true),
713713 .struct_init_anon => try sema.zirStructInitAnon(block, inst, false),
714714 .struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true),
715 .array_init => try sema.zirArrayInit(block, inst, false),
716 .array_init_ref => try sema.zirArrayInit(block, inst, true),
715 .array_init => try sema.zirArrayInit(block, inst, false, false),
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),
717719 .array_init_anon => try sema.zirArrayInitAnon(block, inst, false),
718720 .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true),
719721 .union_init => try sema.zirUnionInit(block, inst),
......@@ -11782,6 +11784,7 @@ fn zirArrayInit(
1178211784 block: *Block,
1178311785 inst: Zir.Inst.Index,
1178411786 is_ref: bool,
11787 is_sent: bool,
1178511788) CompileError!Air.Inst.Ref {
1178611789 const gpa = sema.gpa;
1178711790 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
......@@ -11796,23 +11799,28 @@ fn zirArrayInit(
1179611799
1179711800 for (args) |arg, i| resolved_args[i] = sema.resolveInst(arg);
1179811801
11799 const elem_ty = sema.typeOf(resolved_args[1]);
11800 const array_ty = switch (resolved_args[0]) {
11801 .none => try Type.Tag.array.create(sema.arena, .{
11802 .len = resolved_args.len,
11803 .elem_type = elem_ty,
11804 }),
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 }
1180511810
11806 else => |ref| blk: {
11807 assert(sema.typeOf(ref).zigTypeTag() == .Type);
11808 var buffer: Value.ToTypeBuffer = undefined;
11809 const val = try sema.resolveConstValue(block, src, ref);
11810 const ty = val.toType(&buffer);
11811 break :blk try ty.copy(sema.arena);
11812 },
11811 const sentinel_ref = resolved_args[resolved_args.len - 1];
11812 const val = try sema.resolveConstValue(block, src, sentinel_ref);
11813 break :blk try Type.Tag.array_sentinel.create(sema.arena, .{
11814 .len = resolved_args.len - 1,
11815 .sentinel = val,
11816 .elem_type = elem_ty,
11817 });
1181311818 };
1181411819
11815 const elems = resolved_args[1..];
11820 const elems = if (!is_sent)
11821 resolved_args
11822 else
11823 resolved_args[0 .. resolved_args.len - 1];
1181611824
1181711825 const opt_runtime_src: ?LazySrcLoc = for (elems) |arg| {
1181811826 const arg_src = src; // TODO better source location
src/Zir.zig+12
......@@ -710,12 +710,20 @@ pub const Inst = struct {
710710 /// Array initialization syntax.
711711 /// Uses the `pl_node` field. Payload is `MultiOp`.
712712 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,
713717 /// Anonymous array initialization syntax.
714718 /// Uses the `pl_node` field. Payload is `MultiOp`.
715719 array_init_anon,
716720 /// Array initialization syntax, make the result a pointer.
717721 /// Uses the `pl_node` field. Payload is `MultiOp`.
718722 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,
719727 /// Anonymous array initialization syntax, make the result a pointer.
720728 /// Uses the `pl_node` field. Payload is `MultiOp`.
721729 array_init_anon_ref,
......@@ -1119,8 +1127,10 @@ pub const Inst = struct {
11191127 .struct_init_anon,
11201128 .struct_init_anon_ref,
11211129 .array_init,
1130 .array_init_sent,
11221131 .array_init_anon,
11231132 .array_init_ref,
1133 .array_init_sent_ref,
11241134 .array_init_anon_ref,
11251135 .union_init,
11261136 .field_type,
......@@ -1377,8 +1387,10 @@ pub const Inst = struct {
13771387 .struct_init_anon = .pl_node,
13781388 .struct_init_anon_ref = .pl_node,
13791389 .array_init = .pl_node,
1390 .array_init_sent = .pl_node,
13801391 .array_init_anon = .pl_node,
13811392 .array_init_ref = .pl_node,
1393 .array_init_sent_ref = .pl_node,
13821394 .array_init_anon_ref = .pl_node,
13831395 .union_init = .pl_node,
13841396 .type_info = .un_node,
src/print_zir.zig+24
......@@ -269,6 +269,10 @@ const Writer = struct {
269269 .array_init_anon_ref,
270270 => try self.writeArrayInit(stream, inst),
271271
272 .array_init_sent,
273 .array_init_sent_ref,
274 => try self.writeArrayInitSent(stream, inst),
275
272276 .slice_start => try self.writeSliceStart(stream, inst),
273277 .slice_end => try self.writeSliceEnd(stream, inst),
274278 .slice_sentinel => try self.writeSliceSentinel(stream, inst),
......@@ -2022,6 +2026,26 @@ const Writer = struct {
20222026 try self.writeSrc(stream, inst_data.src());
20232027 }
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
20252049 fn writeUnreachable(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
20262050 const inst_data = self.code.instructions.items(.data)[inst].@"unreachable";
20272051 const safety_str = if (inst_data.safety) "safe" else "unsafe";