| 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,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 | }; |
| 1267 | 1269 | ||
| 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 | }; |
| 1312 | 1317 | ||
| ... | @@ -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, types.array, .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, types.array, .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, types.array, .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, types.array, .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,18 +1392,32 @@ fn arrayInitExprRlTy( | ... | @@ -1387,18 +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 | array_ty: Zir.Inst.Ref, | 1395 | sentinel: Zir.Inst.Ref, |
| 1391 | tag: Zir.Inst.Tag, | 1396 | ref: bool, |
| 1392 | ) InnerError!Zir.Inst.Ref { | 1397 | ) InnerError!Zir.Inst.Ref { |
| 1393 | const astgen = gz.astgen; | 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 | const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{ | 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); | 1420 | var extra_index = try reserveExtra(astgen, info.len); |
| 1399 | |||
| 1400 | astgen.extra.items[extra_index] = @enumToInt(array_ty); | ||
| 1401 | extra_index += 1; | ||
| 1402 | 1421 | ||
| 1403 | const elem_rl: ResultLoc = .{ .ty = elem_ty_inst }; | 1422 | const elem_rl: ResultLoc = .{ .ty = elem_ty_inst }; |
| 1404 | for (elements) |elem_init| { | 1423 | for (elements) |elem_init| { |
| ... | @@ -1406,7 +1425,13 @@ fn arrayInitExprRlTy( | ... | @@ -1406,7 +1425,13 @@ fn arrayInitExprRlTy( |
| 1406 | astgen.extra.items[extra_index] = @enumToInt(elem_ref); | 1425 | astgen.extra.items[extra_index] = @enumToInt(elem_ref); |
| 1407 | extra_index += 1; | 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 | fn arrayInitExprRlPtr( | 1437 | fn arrayInitExprRlPtr( |
| ... | @@ -2221,8 +2246,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner | ... | @@ -2221,8 +2246,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2221 | .struct_init_anon_ref, | 2246 | .struct_init_anon_ref, |
| 2222 | .array_init, | 2247 | .array_init, |
| 2223 | .array_init_anon, | 2248 | .array_init_anon, |
| 2249 | .array_init_sent, | ||
| 2224 | .array_init_ref, | 2250 | .array_init_ref, |
| 2225 | .array_init_anon_ref, | 2251 | .array_init_anon_ref, |
| 2252 | .array_init_sent_ref, | ||
| 2226 | .union_init, | 2253 | .union_init, |
| 2227 | .field_type, | 2254 | .field_type, |
| 2228 | .field_type_ref, | 2255 | .field_type_ref, |
src/Sema.zig+24-16| ... | @@ -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; |
| ... | @@ -11796,23 +11799,28 @@ fn zirArrayInit( | ... | @@ -11796,23 +11799,28 @@ fn zirArrayInit( |
| 11796 | 11799 | ||
| 11797 | for (args) |arg, i| resolved_args[i] = sema.resolveInst(arg); | 11800 | for (args) |arg, i| resolved_args[i] = sema.resolveInst(arg); |
| 11798 | 11801 | ||
| 11799 | const elem_ty = sema.typeOf(resolved_args[1]); | 11802 | const elem_ty = sema.typeOf(resolved_args[0]); |
| 11800 | const array_ty = switch (resolved_args[0]) { | 11803 | const array_ty = blk: { |
| 11801 | .none => try Type.Tag.array.create(sema.arena, .{ | 11804 | if (!is_sent) { |
| 11802 | .len = resolved_args.len, | 11805 | break :blk try Type.Tag.array.create(sema.arena, .{ |
| 11803 | .elem_type = elem_ty, | 11806 | .len = resolved_args.len, |
| 11804 | }), | 11807 | .elem_type = elem_ty, |
| 11808 | }); | ||
| 11809 | } | ||
| 11805 | 11810 | ||
| 11806 | else => |ref| blk: { | 11811 | const sentinel_ref = resolved_args[resolved_args.len - 1]; |
| 11807 | assert(sema.typeOf(ref).zigTypeTag() == .Type); | 11812 | const val = try sema.resolveConstValue(block, src, sentinel_ref); |
| 11808 | var buffer: Value.ToTypeBuffer = undefined; | 11813 | break :blk try Type.Tag.array_sentinel.create(sema.arena, .{ |
| 11809 | const val = try sema.resolveConstValue(block, src, ref); | 11814 | .len = resolved_args.len - 1, |
| 11810 | const ty = val.toType(&buffer); | 11815 | .sentinel = val, |
| 11811 | break :blk try ty.copy(sema.arena); | 11816 | .elem_type = elem_ty, |
| 11812 | }, | 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 | const opt_runtime_src: ?LazySrcLoc = for (elems) |arg| { | 11825 | const opt_runtime_src: ?LazySrcLoc = for (elems) |arg| { |
| 11818 | const arg_src = src; // TODO better source location | 11826 | const arg_src = src; // TODO better source location |
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, |
| ... | @@ -1119,8 +1127,10 @@ pub const Inst = struct { | ... | @@ -1119,8 +1127,10 @@ pub const Inst = struct { |
| 1119 | .struct_init_anon, | 1127 | .struct_init_anon, |
| 1120 | .struct_init_anon_ref, | 1128 | .struct_init_anon_ref, |
| 1121 | .array_init, | 1129 | .array_init, |
| 1130 | .array_init_sent, | ||
| 1122 | .array_init_anon, | 1131 | .array_init_anon, |
| 1123 | .array_init_ref, | 1132 | .array_init_ref, |
| 1133 | .array_init_sent_ref, | ||
| 1124 | .array_init_anon_ref, | 1134 | .array_init_anon_ref, |
| 1125 | .union_init, | 1135 | .union_init, |
| 1126 | .field_type, | 1136 | .field_type, |
| ... | @@ -1377,8 +1387,10 @@ pub const Inst = struct { | ... | @@ -1377,8 +1387,10 @@ pub const Inst = struct { |
| 1377 | .struct_init_anon = .pl_node, | 1387 | .struct_init_anon = .pl_node, |
| 1378 | .struct_init_anon_ref = .pl_node, | 1388 | .struct_init_anon_ref = .pl_node, |
| 1379 | .array_init = .pl_node, | 1389 | .array_init = .pl_node, |
| 1390 | .array_init_sent = .pl_node, | ||
| 1380 | .array_init_anon = .pl_node, | 1391 | .array_init_anon = .pl_node, |
| 1381 | .array_init_ref = .pl_node, | 1392 | .array_init_ref = .pl_node, |
| 1393 | .array_init_sent_ref = .pl_node, | ||
| 1382 | .array_init_anon_ref = .pl_node, | 1394 | .array_init_anon_ref = .pl_node, |
| 1383 | .union_init = .pl_node, | 1395 | .union_init = .pl_node, |
| 1384 | .type_info = .un_node, | 1396 | .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), |
| 271 | 271 | ||
| 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 | } |
| 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 | 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"; |