| author | |
| committer | |
| log | 85b0a4a8fd8a56c07e0377b02d33753fe205fe41 |
| tree | 175a059ce3b60e6da72cc1e3c70b37d0af54a216 |
| parent | c9fac41368c872d424681ea3cf93a9d97157143e |
| signature |
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( |
| 1259 | 1259 | const types: struct { |
| 1260 | 1260 | array: Zir.Inst.Ref, |
| 1261 | 1261 | elem: Zir.Inst.Ref, |
| 1262 | sentinel: Zir.Inst.Ref, | |
| 1262 | 1263 | } = inst: { |
| 1263 | 1264 | if (array_init.ast.type_expr == 0) break :inst .{ |
| 1264 | 1265 | .array = .none, |
| 1265 | 1266 | .elem = .none, |
| 1267 | .sentinel = .none, | |
| 1266 | 1268 | }; |
| 1267 | 1269 | |
| 1268 | 1270 | infer: { |
| ... | ... | @@ -1282,6 +1284,7 @@ fn arrayInitExpr( |
| 1282 | 1284 | break :inst .{ |
| 1283 | 1285 | .array = array_type_inst, |
| 1284 | 1286 | .elem = elem_type, |
| 1287 | .sentinel = .none, | |
| 1285 | 1288 | }; |
| 1286 | 1289 | } else { |
| 1287 | 1290 | const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel); |
| ... | ... | @@ -1297,6 +1300,7 @@ fn arrayInitExpr( |
| 1297 | 1300 | break :inst .{ |
| 1298 | 1301 | .array = array_type_inst, |
| 1299 | 1302 | .elem = elem_type, |
| 1303 | .sentinel = sentinel, | |
| 1300 | 1304 | }; |
| 1301 | 1305 | } |
| 1302 | 1306 | } |
| ... | ... | @@ -1307,6 +1311,7 @@ fn arrayInitExpr( |
| 1307 | 1311 | break :inst .{ |
| 1308 | 1312 | .array = array_type_inst, |
| 1309 | 1313 | .elem = elem_type, |
| 1314 | .sentinel = .none, | |
| 1310 | 1315 | }; |
| 1311 | 1316 | }; |
| 1312 | 1317 | |
| ... | ... | @@ -1319,25 +1324,25 @@ fn arrayInitExpr( |
| 1319 | 1324 | }, |
| 1320 | 1325 | .ref => { |
| 1321 | 1326 | 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); | |
| 1323 | 1328 | } else { |
| 1324 | 1329 | return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref); |
| 1325 | 1330 | } |
| 1326 | 1331 | }, |
| 1327 | 1332 | .none => { |
| 1328 | 1333 | 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); | |
| 1330 | 1335 | } else { |
| 1331 | 1336 | return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); |
| 1332 | 1337 | } |
| 1333 | 1338 | }, |
| 1334 | 1339 | .ty, .coerced_ty => |ty_inst| { |
| 1335 | 1340 | 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); | |
| 1337 | 1342 | return rvalue(gz, rl, result, node); |
| 1338 | 1343 | } else { |
| 1339 | 1344 | 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); | |
| 1341 | 1346 | } |
| 1342 | 1347 | }, |
| 1343 | 1348 | .ptr => |ptr_inst| { |
| ... | ... | @@ -1387,18 +1392,32 @@ fn arrayInitExprRlTy( |
| 1387 | 1392 | node: Ast.Node.Index, |
| 1388 | 1393 | elements: []const Ast.Node.Index, |
| 1389 | 1394 | 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, | |
| 1392 | 1397 | ) InnerError!Zir.Inst.Ref { |
| 1393 | 1398 | const astgen = gz.astgen; |
| 1394 | 1399 | |
| 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 | ||
| 1395 | 1417 | const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{ |
| 1396 | .operands_len = @intCast(u32, elements.len + 1), | |
| 1418 | .operands_len = @intCast(u32, info.len), | |
| 1397 | 1419 | }); |
| 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); | |
| 1402 | 1421 | |
| 1403 | 1422 | const elem_rl: ResultLoc = .{ .ty = elem_ty_inst }; |
| 1404 | 1423 | for (elements) |elem_init| { |
| ... | ... | @@ -1406,7 +1425,13 @@ fn arrayInitExprRlTy( |
| 1406 | 1425 | astgen.extra.items[extra_index] = @enumToInt(elem_ref); |
| 1407 | 1426 | extra_index += 1; |
| 1408 | 1427 | } |
| 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); | |
| 1410 | 1435 | } |
| 1411 | 1436 | |
| 1412 | 1437 | fn arrayInitExprRlPtr( |
| ... | ... | @@ -2221,8 +2246,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2221 | 2246 | .struct_init_anon_ref, |
| 2222 | 2247 | .array_init, |
| 2223 | 2248 | .array_init_anon, |
| 2249 | .array_init_sent, | |
| 2224 | 2250 | .array_init_ref, |
| 2225 | 2251 | .array_init_anon_ref, |
| 2252 | .array_init_sent_ref, | |
| 2226 | 2253 | .union_init, |
| 2227 | 2254 | .field_type, |
| 2228 | 2255 | .field_type_ref, |
src/Sema.zig+24-16| ... | ... | @@ -712,8 +712,10 @@ fn analyzeBodyInner( |
| 712 | 712 | .struct_init_ref => try sema.zirStructInit(block, inst, true), |
| 713 | 713 | .struct_init_anon => try sema.zirStructInitAnon(block, inst, false), |
| 714 | 714 | .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), | |
| 717 | 719 | .array_init_anon => try sema.zirArrayInitAnon(block, inst, false), |
| 718 | 720 | .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true), |
| 719 | 721 | .union_init => try sema.zirUnionInit(block, inst), |
| ... | ... | @@ -11782,6 +11784,7 @@ fn zirArrayInit( |
| 11782 | 11784 | block: *Block, |
| 11783 | 11785 | inst: Zir.Inst.Index, |
| 11784 | 11786 | is_ref: bool, |
| 11787 | is_sent: bool, | |
| 11785 | 11788 | ) CompileError!Air.Inst.Ref { |
| 11786 | 11789 | const gpa = sema.gpa; |
| 11787 | 11790 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| ... | ... | @@ -11796,23 +11799,28 @@ fn zirArrayInit( |
| 11796 | 11799 | |
| 11797 | 11800 | for (args) |arg, i| resolved_args[i] = sema.resolveInst(arg); |
| 11798 | 11801 | |
| 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 | } | |
| 11805 | 11810 | |
| 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 | }); | |
| 11813 | 11818 | }; |
| 11814 | 11819 | |
| 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]; | |
| 11816 | 11824 | |
| 11817 | 11825 | const opt_runtime_src: ?LazySrcLoc = for (elems) |arg| { |
| 11818 | 11826 | const arg_src = src; // TODO better source location |
src/Zir.zig+12| ... | ... | @@ -710,12 +710,20 @@ pub const Inst = struct { |
| 710 | 710 | /// Array initialization syntax. |
| 711 | 711 | /// Uses the `pl_node` field. Payload is `MultiOp`. |
| 712 | 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 | 717 | /// Anonymous array initialization syntax. |
| 714 | 718 | /// Uses the `pl_node` field. Payload is `MultiOp`. |
| 715 | 719 | array_init_anon, |
| 716 | 720 | /// Array initialization syntax, make the result a pointer. |
| 717 | 721 | /// Uses the `pl_node` field. Payload is `MultiOp`. |
| 718 | 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 | 727 | /// Anonymous array initialization syntax, make the result a pointer. |
| 720 | 728 | /// Uses the `pl_node` field. Payload is `MultiOp`. |
| 721 | 729 | array_init_anon_ref, |
| ... | ... | @@ -1119,8 +1127,10 @@ pub const Inst = struct { |
| 1119 | 1127 | .struct_init_anon, |
| 1120 | 1128 | .struct_init_anon_ref, |
| 1121 | 1129 | .array_init, |
| 1130 | .array_init_sent, | |
| 1122 | 1131 | .array_init_anon, |
| 1123 | 1132 | .array_init_ref, |
| 1133 | .array_init_sent_ref, | |
| 1124 | 1134 | .array_init_anon_ref, |
| 1125 | 1135 | .union_init, |
| 1126 | 1136 | .field_type, |
| ... | ... | @@ -1377,8 +1387,10 @@ pub const Inst = struct { |
| 1377 | 1387 | .struct_init_anon = .pl_node, |
| 1378 | 1388 | .struct_init_anon_ref = .pl_node, |
| 1379 | 1389 | .array_init = .pl_node, |
| 1390 | .array_init_sent = .pl_node, | |
| 1380 | 1391 | .array_init_anon = .pl_node, |
| 1381 | 1392 | .array_init_ref = .pl_node, |
| 1393 | .array_init_sent_ref = .pl_node, | |
| 1382 | 1394 | .array_init_anon_ref = .pl_node, |
| 1383 | 1395 | .union_init = .pl_node, |
| 1384 | 1396 | .type_info = .un_node, |
src/print_zir.zig+24| ... | ... | @@ -269,6 +269,10 @@ const Writer = struct { |
| 269 | 269 | .array_init_anon_ref, |
| 270 | 270 | => try self.writeArrayInit(stream, inst), |
| 271 | 271 | |
| 272 | .array_init_sent, | |
| 273 | .array_init_sent_ref, | |
| 274 | => try self.writeArrayInitSent(stream, inst), | |
| 275 | ||
| 272 | 276 | .slice_start => try self.writeSliceStart(stream, inst), |
| 273 | 277 | .slice_end => try self.writeSliceEnd(stream, inst), |
| 274 | 278 | .slice_sentinel => try self.writeSliceSentinel(stream, inst), |
| ... | ... | @@ -2022,6 +2026,26 @@ const Writer = struct { |
| 2022 | 2026 | try self.writeSrc(stream, inst_data.src()); |
| 2023 | 2027 | } |
| 2024 | 2028 | |
| 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 | 2049 | fn writeUnreachable(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { |
| 2026 | 2050 | const inst_data = self.code.instructions.items(.data)[inst].@"unreachable"; |
| 2027 | 2051 | const safety_str = if (inst_data.safety) "safe" else "unsafe"; |