authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-19 23:06:19-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-19 23:15:18-07:00
log56677f2f2da41af5999b84b7f740d7bc463d1032
treeacc501152db65974b9e381d72de6c6dc385ad667
parent937c43ddf1297f355cc535adf3ec08f9f741b6c8

astgen: support blocks

We are now passing this test: ```zig export fn _start() noreturn {} ``` ``` test.zig:1:30: error: expected noreturn, found void ``` I ran into an issue where we get an integer overflow trying to compute node index offsets from the containing Decl. The problem is that the parser adds the Decl node after adding the child nodes. For some things, it is easy to reserve the node index and then set it later, however, for this case, it is not a trivial code change, because depending on tokens after parsing the decl determines whether we want to add a new node or not. Possible strategies here: 1. Rework the parser code to make sure that Decl nodes are before children nodes in the AST node array. 2. Use signed integers for Decl node offsets. 3. Just flip the order of subtraction and addition. Expect Decl Node index to be greater than children Node indexes. I opted for (3) because it seems like the simplest thing to do. We'll want to unify the logic for computing the offsets though because if the logic gets repeated, it will probably get repeated wrong.

7 files changed, 398 insertions(+), 109 deletions(-)

BRANCH_TODO+3-19
......@@ -1,9 +1,6 @@
11this is my WIP branch scratch pad, to be deleted before merging into master
22
33Merge TODO list:
4 * fix discrepancy between TZIR wanting src: usize (byte offset) and Sema
5 now providing LazySrcLoc
6 * fix compile errors
74 * don't have an explicit dbg_stmt zir instruction - instead merge it with
85 var decl and assignment instructions, etc.
96 - make it set sema.src where appropriate
......@@ -13,6 +10,7 @@ Merge TODO list:
1310 * finish implementing SrcLoc byteOffset function
1411 * audit Module.zig for use of token_starts - it should only be when
1512 resolving LazySrcLoc
13 * audit astgen.zig for use of token_starts - I think there should be no uses
1614 * audit all the .unneeded src locations
1715 * audit the calls in codegen toSrcLocWithDecl specifically if there is inlined function
1816 calls from other files.
......@@ -29,20 +27,6 @@ Performance optimizations to look into:
2927 - Look into this for enum literals too
3028 * make ret_type and ret_ptr instructions be implied indexes; no need to have
3129 tags associated with them.
32
33
34Random snippets of code that I deleted and need to make sure get
35re-integrated appropriately:
36
37
38
39 /// Each Decl gets its own string interning, in order to avoid contention when
40 /// using multiple threads to analyze Decls in parallel. Any particular Decl will only
41 /// be touched by a single thread at one time.
42 strings: StringTable = .{},
43
44 /// The string memory referenced here is stored inside the Decl's arena.
45 pub const StringTable = std.StringArrayHashMapUnmanaged(void);
46
47
30 * use a smaller encoding for the auto generated return void at the end of
31 function ZIR.
4832
lib/std/zig/parse.zig+20-5
......@@ -139,6 +139,16 @@ const Parser = struct {
139139 return result;
140140 }
141141
142 fn setNode(p: *Parser, i: usize, elem: ast.NodeList.Elem) Node.Index {
143 p.nodes.set(i, elem);
144 return @intCast(Node.Index, i);
145 }
146
147 fn reserveNode(p: *Parser) !usize {
148 try p.nodes.resize(p.gpa, p.nodes.len + 1);
149 return p.nodes.len - 1;
150 }
151
142152 fn addExtra(p: *Parser, extra: anytype) Allocator.Error!Node.Index {
143153 const fields = std.meta.fields(@TypeOf(extra));
144154 try p.extra_data.ensureCapacity(p.gpa, p.extra_data.items.len + fields.len);
......@@ -554,9 +564,10 @@ const Parser = struct {
554564 return fn_proto;
555565 },
556566 .l_brace => {
567 const fn_decl_index = try p.reserveNode();
557568 const body_block = try p.parseBlock();
558569 assert(body_block != 0);
559 return p.addNode(.{
570 return p.setNode(fn_decl_index, .{
560571 .tag = .fn_decl,
561572 .main_token = p.nodes.items(.main_token)[fn_proto],
562573 .data = .{
......@@ -634,6 +645,10 @@ const Parser = struct {
634645 /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? CallConv? EXCLAMATIONMARK? (Keyword_anytype / TypeExpr)
635646 fn parseFnProto(p: *Parser) !Node.Index {
636647 const fn_token = p.eatToken(.keyword_fn) orelse return null_node;
648
649 // We want the fn proto node to be before its children in the array.
650 const fn_proto_index = try p.reserveNode();
651
637652 _ = p.eatToken(.identifier);
638653 const params = try p.parseParamDeclList();
639654 defer params.deinit(p.gpa);
......@@ -651,7 +666,7 @@ const Parser = struct {
651666
652667 if (align_expr == 0 and section_expr == 0 and callconv_expr == 0) {
653668 switch (params) {
654 .zero_or_one => |param| return p.addNode(.{
669 .zero_or_one => |param| return p.setNode(fn_proto_index, .{
655670 .tag = .fn_proto_simple,
656671 .main_token = fn_token,
657672 .data = .{
......@@ -661,7 +676,7 @@ const Parser = struct {
661676 }),
662677 .multi => |list| {
663678 const span = try p.listToSpan(list);
664 return p.addNode(.{
679 return p.setNode(fn_proto_index, .{
665680 .tag = .fn_proto_multi,
666681 .main_token = fn_token,
667682 .data = .{
......@@ -676,7 +691,7 @@ const Parser = struct {
676691 }
677692 }
678693 switch (params) {
679 .zero_or_one => |param| return p.addNode(.{
694 .zero_or_one => |param| return p.setNode(fn_proto_index, .{
680695 .tag = .fn_proto_one,
681696 .main_token = fn_token,
682697 .data = .{
......@@ -691,7 +706,7 @@ const Parser = struct {
691706 }),
692707 .multi => |list| {
693708 const span = try p.listToSpan(list);
694 return p.addNode(.{
709 return p.setNode(fn_proto_index, .{
695710 .tag = .fn_proto,
696711 .main_token = fn_token,
697712 .data = .{
src/Compilation.zig+2-2
......@@ -317,7 +317,7 @@ pub const AllErrors = struct {
317317 for (notes) |*note, i| {
318318 const module_note = module_err_msg.notes[i];
319319 const source = try module_note.src_loc.fileScope().getSource(module);
320 const byte_offset = try module_note.src_loc.byteOffset(module);
320 const byte_offset = try module_note.src_loc.byteOffset();
321321 const loc = std.zig.findLineColumn(source, byte_offset);
322322 const sub_file_path = module_note.src_loc.fileScope().sub_file_path;
323323 note.* = .{
......@@ -331,7 +331,7 @@ pub const AllErrors = struct {
331331 };
332332 }
333333 const source = try module_err_msg.src_loc.fileScope().getSource(module);
334 const byte_offset = try module_err_msg.src_loc.byteOffset(module);
334 const byte_offset = try module_err_msg.src_loc.byteOffset();
335335 const loc = std.zig.findLineColumn(source, byte_offset);
336336 const sub_file_path = module_err_msg.src_loc.fileScope().sub_file_path;
337337 try errors.append(.{
src/Module.zig+230-12
......@@ -241,6 +241,10 @@ pub const Decl = struct {
241241 return .{ .token_offset = token_index - decl.srcToken() };
242242 }
243243
244 pub fn nodeSrcLoc(decl: *Decl, node_index: ast.Node.Index) LazySrcLoc {
245 return .{ .node_offset = node_index - decl.srcNode() };
246 }
247
244248 pub fn srcLoc(decl: *Decl) SrcLoc {
245249 return .{
246250 .container = .{ .decl = decl },
......@@ -1003,10 +1007,14 @@ pub const Scope = struct {
10031007 };
10041008 }
10051009
1006 pub fn tokSrcLoc(gz: *GenZir, token_index: ast.TokenIndex) LazySrcLoc {
1010 pub fn tokSrcLoc(gz: GenZir, token_index: ast.TokenIndex) LazySrcLoc {
10071011 return gz.zir_code.decl.tokSrcLoc(token_index);
10081012 }
10091013
1014 pub fn nodeSrcLoc(gz: GenZir, node_index: ast.Node.Index) LazySrcLoc {
1015 return gz.zir_code.decl.nodeSrcLoc(node_index);
1016 }
1017
10101018 pub fn addFnTypeCc(gz: *GenZir, tag: zir.Inst.Tag, args: struct {
10111019 param_types: []const zir.Inst.Ref,
10121020 ret_ty: zir.Inst.Ref,
......@@ -1092,6 +1100,30 @@ pub const Scope = struct {
10921100 });
10931101 }
10941102
1103 pub fn addPlNode(
1104 gz: *GenZir,
1105 tag: zir.Inst.Tag,
1106 /// Absolute node index. This function does the conversion to offset from Decl.
1107 abs_node_index: ast.Node.Index,
1108 extra: anytype,
1109 ) !zir.Inst.Ref {
1110 const gpa = gz.zir_code.gpa;
1111 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
1112 try gz.zir_code.instructions.ensureCapacity(gpa, gz.zir_code.instructions.len + 1);
1113
1114 const payload_index = try gz.zir_code.addExtra(extra);
1115 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
1116 gz.zir_code.instructions.appendAssumeCapacity(.{
1117 .tag = tag,
1118 .data = .{ .pl_node = .{
1119 .src_node = gz.zir_code.decl.srcNode() - abs_node_index,
1120 .payload_index = payload_index,
1121 } },
1122 });
1123 gz.instructions.appendAssumeCapacity(new_index);
1124 return new_index + gz.zir_code.ref_start_index;
1125 }
1126
10951127 pub fn addUnTok(
10961128 gz: *GenZir,
10971129 tag: zir.Inst.Tag,
......@@ -1165,6 +1197,21 @@ pub const Scope = struct {
11651197 });
11661198 }
11671199
1200 /// Note that this returns a `zir.Inst.Index` not a ref.
1201 /// Does *not* append the block instruction to the scope.
1202 /// Leaves the `payload_index` field undefined.
1203 pub fn addBlock(gz: *GenZir, tag: zir.Inst.Tag, node: ast.Node.Index) !zir.Inst.Index {
1204 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
1205 try gz.zir_code.instructions.append(gz.zir_code.gpa, .{
1206 .tag = tag,
1207 .data = .{ .pl_node = .{
1208 .src_node = node - gz.zir_code.decl.srcNode(),
1209 .payload_index = undefined,
1210 } },
1211 });
1212 return new_index;
1213 }
1214
11681215 fn add(gz: *GenZir, inst: zir.Inst) !zir.Inst.Ref {
11691216 const gpa = gz.zir_code.gpa;
11701217 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
......@@ -1188,6 +1235,8 @@ pub const Scope = struct {
11881235 gen_zir: *GenZir,
11891236 name: []const u8,
11901237 inst: zir.Inst.Index,
1238 /// Source location of the corresponding variable declaration.
1239 src: LazySrcLoc,
11911240 };
11921241
11931242 /// This could be a `const` or `var` local. It has a pointer instead of a value.
......@@ -1201,6 +1250,8 @@ pub const Scope = struct {
12011250 gen_zir: *GenZir,
12021251 name: []const u8,
12031252 ptr: zir.Inst.Index,
1253 /// Source location of the corresponding variable declaration.
1254 src: LazySrcLoc,
12041255 };
12051256
12061257 pub const Nosuspend = struct {
......@@ -1246,6 +1297,169 @@ pub const WipZirCode = struct {
12461297 return result;
12471298 }
12481299
1300 /// Returns `true` if and only if the instruction *always* has a void type, or
1301 /// *always* has a NoReturn type. Function calls return false because
1302 /// the answer depends on their type.
1303 /// This is used to elide unnecessary `ensure_result_used` instructions.
1304 pub fn isVoidOrNoReturn(wzc: WipZirCode, inst_ref: zir.Inst.Ref) bool {
1305 if (inst_ref >= wzc.ref_start_index) {
1306 const inst = inst_ref - wzc.ref_start_index;
1307 const tags = wzc.instructions.items(.tag);
1308 switch (tags[inst]) {
1309 .@"const" => {
1310 const tv = wzc.instructions.items(.data)[inst].@"const";
1311 return switch (tv.ty.zigTypeTag()) {
1312 .NoReturn, .Void => true,
1313 else => false,
1314 };
1315 },
1316
1317 .add,
1318 .addwrap,
1319 .alloc,
1320 .alloc_mut,
1321 .alloc_inferred,
1322 .alloc_inferred_mut,
1323 .array_cat,
1324 .array_mul,
1325 .array_type,
1326 .array_type_sentinel,
1327 .indexable_ptr_len,
1328 .as,
1329 .as_node,
1330 .@"asm",
1331 .asm_volatile,
1332 .bit_and,
1333 .bitcast,
1334 .bitcast_ref,
1335 .bitcast_result_ptr,
1336 .bit_or,
1337 .block,
1338 .block_flat,
1339 .block_comptime,
1340 .block_comptime_flat,
1341 .bool_not,
1342 .bool_and,
1343 .bool_or,
1344 .call,
1345 .call_async_kw,
1346 .call_no_async,
1347 .call_compile_time,
1348 .call_none,
1349 .cmp_lt,
1350 .cmp_lte,
1351 .cmp_eq,
1352 .cmp_gte,
1353 .cmp_gt,
1354 .cmp_neq,
1355 .coerce_result_ptr,
1356 .decl_ref,
1357 .decl_val,
1358 .deref_node,
1359 .div,
1360 .elem_ptr,
1361 .elem_val,
1362 .elem_ptr_node,
1363 .elem_val_node,
1364 .floatcast,
1365 .field_ptr,
1366 .field_val,
1367 .field_ptr_named,
1368 .field_val_named,
1369 .fn_type,
1370 .fn_type_var_args,
1371 .fn_type_cc,
1372 .fn_type_cc_var_args,
1373 .int,
1374 .intcast,
1375 .int_type,
1376 .is_non_null,
1377 .is_null,
1378 .is_non_null_ptr,
1379 .is_null_ptr,
1380 .is_err,
1381 .is_err_ptr,
1382 .mod_rem,
1383 .mul,
1384 .mulwrap,
1385 .param_type,
1386 .ptrtoint,
1387 .ref,
1388 .ret_ptr,
1389 .ret_type,
1390 .shl,
1391 .shr,
1392 .store,
1393 .store_to_block_ptr,
1394 .store_to_inferred_ptr,
1395 .str,
1396 .sub,
1397 .subwrap,
1398 .typeof,
1399 .xor,
1400 .optional_type,
1401 .optional_type_from_ptr_elem,
1402 .optional_payload_safe,
1403 .optional_payload_unsafe,
1404 .optional_payload_safe_ptr,
1405 .optional_payload_unsafe_ptr,
1406 .err_union_payload_safe,
1407 .err_union_payload_unsafe,
1408 .err_union_payload_safe_ptr,
1409 .err_union_payload_unsafe_ptr,
1410 .err_union_code,
1411 .err_union_code_ptr,
1412 .ptr_type,
1413 .ptr_type_simple,
1414 .enum_literal,
1415 .enum_literal_small,
1416 .merge_error_sets,
1417 .anyframe_type,
1418 .error_union_type,
1419 .bit_not,
1420 .error_set,
1421 .error_value,
1422 .slice_start,
1423 .slice_end,
1424 .slice_sentinel,
1425 .import,
1426 .typeof_peer,
1427 .resolve_inferred_alloc,
1428 .@"resume",
1429 .@"await",
1430 .nosuspend_await,
1431 => return false,
1432
1433 .breakpoint,
1434 .dbg_stmt_node,
1435 .ensure_result_used,
1436 .ensure_result_non_error,
1437 .set_eval_branch_quota,
1438 .compile_log,
1439 .ensure_err_payload_void,
1440 .@"break",
1441 .break_void_tok,
1442 .condbr,
1443 .compile_error,
1444 .ret_node,
1445 .ret_tok,
1446 .ret_coerce,
1447 .unreachable_unsafe,
1448 .unreachable_safe,
1449 .loop,
1450 .suspend_block,
1451 .suspend_block_one,
1452 .elided,
1453 => return true,
1454 }
1455 }
1456 return switch (inst_ref) {
1457 @enumToInt(zir.Const.unused) => unreachable,
1458 @enumToInt(zir.Const.void_value), @enumToInt(zir.Const.unreachable_value) => true,
1459 else => false,
1460 };
1461 }
1462
12491463 pub fn deinit(wzc: *WipZirCode) void {
12501464 wzc.instructions.deinit(wzc.gpa);
12511465 wzc.extra.deinit(wzc.gpa);
......@@ -1348,7 +1562,7 @@ pub const SrcLoc = struct {
13481562 };
13491563 }
13501564
1351 pub fn byteOffset(src_loc: SrcLoc, mod: *Module) !u32 {
1565 pub fn byteOffset(src_loc: SrcLoc) !u32 {
13521566 switch (src_loc.lazy) {
13531567 .unneeded => unreachable,
13541568 .todo => unreachable,
......@@ -1373,14 +1587,14 @@ pub const SrcLoc = struct {
13731587 .token_offset => |tok_off| {
13741588 const decl = src_loc.container.decl;
13751589 const tok_index = decl.srcToken() + tok_off;
1376 const tree = src_loc.container.file_scope.base.tree();
1590 const tree = decl.container.file_scope.base.tree();
13771591 const token_starts = tree.tokens.items(.start);
13781592 return token_starts[tok_index];
13791593 },
13801594 .node_offset => |node_off| {
13811595 const decl = src_loc.container.decl;
13821596 const node_index = decl.srcNode() + node_off;
1383 const tree = src_loc.container.file_scope.base.tree();
1597 const tree = decl.container.file_scope.base.tree();
13841598 const tok_index = tree.firstToken(node_index);
13851599 const token_starts = tree.tokens.items(.start);
13861600 return token_starts[tok_index];
......@@ -1826,7 +2040,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
18262040
18272041 const code = try gen_scope.finish();
18282042 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
1829 code.dump(mod.gpa, "comptime_block", decl.name, 0) catch {};
2043 code.dump(mod.gpa, "comptime_block", &gen_scope.base, 0) catch {};
18302044 }
18312045 break :blk code;
18322046 };
......@@ -2047,7 +2261,7 @@ fn astgenAndSemaFn(
20472261
20482262 const fn_type_code = try fn_type_scope.finish();
20492263 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
2050 fn_type_code.dump(mod.gpa, "fn_type", decl.name, 0) catch {};
2264 fn_type_code.dump(mod.gpa, "fn_type", &fn_type_scope.base, 0) catch {};
20512265 }
20522266
20532267 var fn_type_sema: Sema = .{
......@@ -2146,6 +2360,7 @@ fn astgenAndSemaFn(
21462360 .name = param_name,
21472361 // Implicit const list first, then implicit arg list.
21482362 .inst = @intCast(u32, zir.const_inst_list.len + i),
2363 .src = decl.tokSrcLoc(name_token),
21492364 };
21502365 params_scope = &sub_scope.base;
21512366
......@@ -2164,13 +2379,16 @@ fn astgenAndSemaFn(
21642379 !wip_zir_code.instructions.items(.tag)[gen_scope.instructions.items.len - 1]
21652380 .isNoReturn())
21662381 {
2167 const void_operand = @enumToInt(zir.Const.void_value);
2168 _ = try gen_scope.addUnTok(.ret_tok, void_operand, tree.lastToken(body_node));
2382 // astgen uses result location semantics to coerce return operands.
2383 // Since we are adding the return instruction here, we must handle the coercion.
2384 // We do this by using the `ret_coerce` instruction.
2385 const void_inst: zir.Inst.Ref = @enumToInt(zir.Const.void_value);
2386 _ = try gen_scope.addUnTok(.ret_coerce, void_inst, tree.lastToken(body_node));
21692387 }
21702388
21712389 const code = try gen_scope.finish();
21722390 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
2173 code.dump(mod.gpa, "fn_body", decl.name, param_count) catch {};
2391 code.dump(mod.gpa, "fn_body", &gen_scope.base, param_count) catch {};
21742392 }
21752393
21762394 break :blk code;
......@@ -2347,7 +2565,7 @@ fn astgenAndSemaVarDecl(
23472565 );
23482566 const code = try gen_scope.finish();
23492567 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
2350 code.dump(mod.gpa, "var_init", decl.name, 0) catch {};
2568 code.dump(mod.gpa, "var_init", &gen_scope.base, 0) catch {};
23512569 }
23522570
23532571 var sema: Sema = .{
......@@ -2409,7 +2627,7 @@ fn astgenAndSemaVarDecl(
24092627 const var_type = try astgen.typeExpr(mod, &type_scope.base, var_decl.ast.type_node);
24102628 const code = try type_scope.finish();
24112629 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
2412 code.dump(mod.gpa, "var_type", decl.name, 0) catch {};
2630 code.dump(mod.gpa, "var_type", &type_scope.base, 0) catch {};
24132631 }
24142632
24152633 var sema: Sema = .{
......@@ -3475,7 +3693,7 @@ pub fn failNode(
34753693 args: anytype,
34763694) InnerError {
34773695 const decl_node = scope.srcDecl().?.srcNode();
3478 const src: LazySrcLoc = .{ .node_offset = node_index - decl_node };
3696 const src: LazySrcLoc = .{ .node_offset = decl_node - node_index };
34793697 return mod.fail(scope, src, format, args);
34803698}
34813699
src/Sema.zig+50-10
......@@ -108,6 +108,7 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde
108108 .dbg_stmt_node => try sema.zirDbgStmtNode(block, zir_inst),
109109 .decl_ref => try sema.zirDeclRef(block, zir_inst),
110110 .decl_val => try sema.zirDeclVal(block, zir_inst),
111 .elided => continue,
111112 .ensure_result_used => try sema.zirEnsureResultUsed(block, zir_inst),
112113 .ensure_result_non_error => try sema.zirEnsureResultNonError(block, zir_inst),
113114 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, zir_inst),
......@@ -133,11 +134,13 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde
133134 .field_val_named => try sema.zirFieldValNamed(block, zir_inst),
134135 .deref_node => try sema.zirDerefNode(block, zir_inst),
135136 .as => try sema.zirAs(block, zir_inst),
137 .as_node => try sema.zirAsNode(block, zir_inst),
136138 .@"asm" => try sema.zirAsm(block, zir_inst, false),
137139 .asm_volatile => try sema.zirAsm(block, zir_inst, true),
138140 .unreachable_safe => try sema.zirUnreachable(block, zir_inst, true),
139141 .unreachable_unsafe => try sema.zirUnreachable(block, zir_inst, false),
140 .ret_tok => try sema.zirRetTok(block, zir_inst),
142 .ret_coerce => try sema.zirRetTok(block, zir_inst, true),
143 .ret_tok => try sema.zirRetTok(block, zir_inst, false),
141144 .ret_node => try sema.zirRetNode(block, zir_inst),
142145 .fn_type => try sema.zirFnType(block, zir_inst, false),
143146 .fn_type_cc => try sema.zirFnTypeCc(block, zir_inst, false),
......@@ -1004,7 +1007,7 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE
10041007 const src_node = sema.code.instructions.items(.data)[inst].node;
10051008 const src: LazySrcLoc = .{ .node_offset = src_node };
10061009 const src_loc = src.toSrcLoc(&block.base);
1007 const abs_byte_off = try src_loc.byteOffset(sema.mod);
1010 const abs_byte_off = try src_loc.byteOffset();
10081011 return block.addDbgStmt(src, abs_byte_off);
10091012}
10101013
......@@ -1767,9 +1770,29 @@ fn zirAs(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Ins
17671770 defer tracy.end();
17681771
17691772 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1770 const dest_type = try sema.resolveType(block, .todo, bin_inst.lhs);
1771 const tzir_inst = try sema.resolveInst(bin_inst.rhs);
1772 return sema.coerce(block, dest_type, tzir_inst, .todo);
1773 return sema.analyzeAs(block, .unneeded, bin_inst.lhs, bin_inst.rhs);
1774}
1775
1776fn zirAsNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1777 const tracy = trace(@src());
1778 defer tracy.end();
1779
1780 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1781 const src = inst_data.src();
1782 const extra = sema.code.extraData(zir.Inst.As, inst_data.payload_index).data;
1783 return sema.analyzeAs(block, src, extra.dest_type, extra.operand);
1784}
1785
1786fn analyzeAs(
1787 sema: *Sema,
1788 block: *Scope.Block,
1789 src: LazySrcLoc,
1790 zir_dest_type: zir.Inst.Ref,
1791 zir_operand: zir.Inst.Ref,
1792) InnerError!*Inst {
1793 const dest_type = try sema.resolveType(block, src, zir_dest_type);
1794 const operand = try sema.resolveInst(zir_operand);
1795 return sema.coerce(block, dest_type, operand, src);
17731796}
17741797
17751798fn zirPtrtoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
......@@ -2850,7 +2873,12 @@ fn zirUnreachable(
28502873 }
28512874}
28522875
2853fn zirRetTok(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2876fn zirRetTok(
2877 sema: *Sema,
2878 block: *Scope.Block,
2879 inst: zir.Inst.Index,
2880 need_coercion: bool,
2881) InnerError!*Inst {
28542882 const tracy = trace(@src());
28552883 defer tracy.end();
28562884
......@@ -2858,7 +2886,7 @@ fn zirRetTok(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!
28582886 const operand = try sema.resolveInst(inst_data.operand);
28592887 const src = inst_data.src();
28602888
2861 return sema.analyzeRet(block, operand, src);
2889 return sema.analyzeRet(block, operand, src, need_coercion);
28622890}
28632891
28642892fn zirRetNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
......@@ -2869,10 +2897,16 @@ fn zirRetNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
28692897 const operand = try sema.resolveInst(inst_data.operand);
28702898 const src = inst_data.src();
28712899
2872 return sema.analyzeRet(block, operand, src);
2900 return sema.analyzeRet(block, operand, src, false);
28732901}
28742902
2875fn analyzeRet(sema: *Sema, block: *Scope.Block, operand: *Inst, src: LazySrcLoc) InnerError!*Inst {
2903fn analyzeRet(
2904 sema: *Sema,
2905 block: *Scope.Block,
2906 operand: *Inst,
2907 src: LazySrcLoc,
2908 need_coercion: bool,
2909) InnerError!*Inst {
28762910 if (block.inlining) |inlining| {
28772911 // We are inlining a function call; rewrite the `ret` as a `break`.
28782912 try inlining.merges.results.append(sema.gpa, operand);
......@@ -2880,7 +2914,13 @@ fn analyzeRet(sema: *Sema, block: *Scope.Block, operand: *Inst, src: LazySrcLoc)
28802914 return &br.base;
28812915 }
28822916
2883 try sema.requireFunctionBlock(block, src);
2917 if (need_coercion) {
2918 if (sema.func) |func| {
2919 const fn_ty = func.owner_decl.typed_value.most_recent.typed_value.ty;
2920 const casted_operand = try sema.coerce(block, fn_ty.fnReturnType(), operand, src);
2921 return block.addUnOp(src, Type.initTag(.noreturn), .ret, casted_operand);
2922 }
2923 }
28842924 return block.addUnOp(src, Type.initTag(.noreturn), .ret, operand);
28852925}
28862926
src/astgen.zig+57-57
......@@ -497,7 +497,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
497497 }
498498 },
499499 .block_two, .block_two_semicolon => {
500 if (true) @panic("TODO update for zir-memory-layout");
501500 const statements = [2]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs };
502501 if (node_datas[node].lhs == 0) {
503502 return blockExpr(mod, scope, rl, node, statements[0..0]);
......@@ -508,7 +507,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
508507 }
509508 },
510509 .block, .block_semicolon => {
511 if (true) @panic("TODO update for zir-memory-layout");
512510 const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];
513511 return blockExpr(mod, scope, rl, node, statements);
514512 },
......@@ -808,7 +806,7 @@ fn breakExpr(
808806 },
809807 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
810808 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
811 .gen_suspend => scope = scope.cast(Scope.GenZIR).?.parent,
809 .gen_suspend => scope = scope.cast(Scope.GenZir).?.parent,
812810 .gen_nosuspend => scope = scope.cast(Scope.Nosuspend).?.parent,
813811 else => if (break_label != 0) {
814812 const label_name = try mod.identifierTokenString(parent_scope, break_label);
......@@ -864,7 +862,7 @@ fn continueExpr(
864862 },
865863 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
866864 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
867 .gen_suspend => scope = scope.cast(Scope.GenZIR).?.parent,
865 .gen_suspend => scope = scope.cast(Scope.GenZir).?.parent,
868866 .gen_nosuspend => scope = scope.cast(Scope.Nosuspend).?.parent,
869867 else => if (break_label != 0) {
870868 const label_name = try mod.identifierTokenString(parent_scope, break_label);
......@@ -939,7 +937,7 @@ fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIn
939937 },
940938 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
941939 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
942 .gen_suspend => scope = scope.cast(Scope.GenZIR).?.parent,
940 .gen_suspend => scope = scope.cast(Scope.GenZir).?.parent,
943941 .gen_nosuspend => scope = scope.cast(Scope.Nosuspend).?.parent,
944942 else => return,
945943 }
......@@ -971,25 +969,14 @@ fn labeledBlockExpr(
971969
972970 try checkLabelRedefinition(mod, parent_scope, label_token);
973971
974 // Create the Block ZIR instruction so that we can put it into the GenZir struct
972 // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct
975973 // so that break statements can reference it.
976 const gen_zir = parent_scope.getGenZir();
977 const block_inst = try gen_zir.arena.create(zir.Inst.Block);
978 block_inst.* = .{
979 .base = .{
980 .tag = zir_tag,
981 .src = src,
982 },
983 .positionals = .{
984 .body = .{ .instructions = undefined },
985 },
986 .kw_args = .{},
987 };
974 const gz = parent_scope.getGenZir();
975 const block_inst = try gz.addBlock(zir_tag, block_node);
988976
989977 var block_scope: Scope.GenZir = .{
990978 .parent = parent_scope,
991 .decl = parent_scope.ownerDecl().?,
992 .arena = gen_zir.arena,
979 .zir_code = gz.zir_code,
993980 .force_comptime = parent_scope.isComptime(),
994981 .instructions = .{},
995982 // TODO @as here is working around a stage1 miscompilation bug :(
......@@ -1009,35 +996,40 @@ fn labeledBlockExpr(
1009996 return mod.failTok(parent_scope, label_token, "unused block label", .{});
1010997 }
1011998
1012 try gen_zir.instructions.append(mod.gpa, &block_inst.base);
999 try gz.instructions.append(mod.gpa, block_inst);
1000
1001 const zir_tags = gz.zir_code.instructions.items(.tag);
1002 const zir_datas = gz.zir_code.instructions.items(.data);
10131003
10141004 const strat = rlStrategy(rl, &block_scope);
10151005 switch (strat.tag) {
10161006 .break_void => {
10171007 // The code took advantage of the result location as a pointer.
1018 // Turn the break instructions into break_void instructions.
1008 // Turn the break instruction operands into void.
10191009 for (block_scope.labeled_breaks.items) |br| {
1020 br.base.tag = .break_void;
1010 zir_datas[br].bin.rhs = 0;
10211011 }
10221012 // TODO technically not needed since we changed the tag to break_void but
10231013 // would be better still to elide the ones that are in this list.
1024 try copyBodyNoEliding(&block_inst.positionals.body, block_scope);
1014 try copyBodyNoEliding(block_inst, block_scope);
10251015
1026 return &block_inst.base;
1016 return gz.zir_code.ref_start_index + block_inst;
10271017 },
10281018 .break_operand => {
10291019 // All break operands are values that did not use the result location pointer.
10301020 if (strat.elide_store_to_block_ptr_instructions) {
10311021 for (block_scope.labeled_store_to_block_ptr_list.items) |inst| {
1032 inst.base.tag = .void_value;
1022 zir_tags[inst] = .elided;
1023 zir_datas[inst] = undefined;
10331024 }
1034 // TODO technically not needed since we changed the tag to void_value but
1025 // TODO technically not needed since we changed the tag to elided but
10351026 // would be better still to elide the ones that are in this list.
10361027 }
1037 try copyBodyNoEliding(&block_inst.positionals.body, block_scope);
1028 try copyBodyNoEliding(block_inst, block_scope);
1029 const block_ref = gz.zir_code.ref_start_index + block_inst;
10381030 switch (rl) {
1039 .ref => return &block_inst.base,
1040 else => return rvalue(mod, parent_scope, rl, &block_inst.base),
1031 .ref => return block_ref,
1032 else => return rvalue(mod, parent_scope, rl, block_ref, block_node),
10411033 }
10421034 },
10431035 }
......@@ -1057,15 +1049,16 @@ fn blockExprStmts(
10571049 var block_arena = std.heap.ArenaAllocator.init(mod.gpa);
10581050 defer block_arena.deinit();
10591051
1052 const gz = parent_scope.getGenZir();
1053
10601054 var scope = parent_scope;
10611055 for (statements) |statement| {
1062 const src = token_starts[tree.firstToken(statement)];
1063 _ = try addZIRNoOp(mod, scope, src, .dbg_stmt);
1056 _ = try gz.addNode(.dbg_stmt_node, statement);
10641057 switch (node_tags[statement]) {
1065 .global_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.globalVarDecl(statement)),
1066 .local_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.localVarDecl(statement)),
1067 .simple_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.simpleVarDecl(statement)),
1068 .aligned_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.alignedVarDecl(statement)),
1058 .global_var_decl => scope = try varDecl(mod, scope, statement, &block_arena.allocator, tree.globalVarDecl(statement)),
1059 .local_var_decl => scope = try varDecl(mod, scope, statement, &block_arena.allocator, tree.localVarDecl(statement)),
1060 .simple_var_decl => scope = try varDecl(mod, scope, statement, &block_arena.allocator, tree.simpleVarDecl(statement)),
1061 .aligned_var_decl => scope = try varDecl(mod, scope, statement, &block_arena.allocator, tree.alignedVarDecl(statement)),
10691062
10701063 .assign => try assign(mod, scope, statement),
10711064 .assign_bit_and => try assignOp(mod, scope, statement, .bit_and),
......@@ -1084,8 +1077,8 @@ fn blockExprStmts(
10841077
10851078 else => {
10861079 const possibly_unused_result = try expr(mod, scope, .none, statement);
1087 if (!possibly_unused_result.tag.isNoReturn()) {
1088 _ = try addZIRUnOp(mod, scope, src, .ensure_result_used, possibly_unused_result);
1080 if (!gz.zir_code.isVoidOrNoReturn(possibly_unused_result)) {
1081 _ = try gz.addUnNode(.ensure_result_used, possibly_unused_result, statement);
10891082 }
10901083 },
10911084 }
......@@ -1095,22 +1088,24 @@ fn blockExprStmts(
10951088fn varDecl(
10961089 mod: *Module,
10971090 scope: *Scope,
1091 node: ast.Node.Index,
10981092 block_arena: *Allocator,
10991093 var_decl: ast.full.VarDecl,
11001094) InnerError!*Scope {
1095 if (true) @panic("TODO update for zir-memory-layout");
1096
11011097 if (var_decl.comptime_token) |comptime_token| {
11021098 return mod.failTok(scope, comptime_token, "TODO implement comptime locals", .{});
11031099 }
11041100 if (var_decl.ast.align_node != 0) {
11051101 return mod.failNode(scope, var_decl.ast.align_node, "TODO implement alignment on locals", .{});
11061102 }
1103 const gz = scope.getGenZir();
11071104 const tree = scope.tree();
1108 const main_tokens = tree.nodes.items(.main_token);
1109 const token_starts = tree.tokens.items(.start);
11101105 const token_tags = tree.tokens.items(.tag);
11111106
11121107 const name_token = var_decl.ast.mut_token + 1;
1113 const name_src = token_starts[name_token];
1108 const name_src = gz.tokSrcLoc(name_token);
11141109 const ident_name = try mod.identifierTokenString(scope, name_token);
11151110
11161111 // Local variables shadowing detection, including function parameters.
......@@ -1125,7 +1120,7 @@ fn varDecl(
11251120 ident_name,
11261121 });
11271122 errdefer msg.destroy(mod.gpa);
1128 try mod.errNote(scope, local_val.inst.src, msg, "previous definition is here", .{});
1123 try mod.errNote(scope, local_val.src, msg, "previous definition is here", .{});
11291124 break :msg msg;
11301125 };
11311126 return mod.failWithOwnedErrorMsg(scope, msg);
......@@ -1140,7 +1135,7 @@ fn varDecl(
11401135 ident_name,
11411136 });
11421137 errdefer msg.destroy(mod.gpa);
1143 try mod.errNote(scope, local_ptr.ptr.src, msg, "previous definition is here", .{});
1138 try mod.errNote(scope, local_ptr.src, msg, "previous definition is here", .{});
11441139 break :msg msg;
11451140 };
11461141 return mod.failWithOwnedErrorMsg(scope, msg);
......@@ -1176,9 +1171,10 @@ fn varDecl(
11761171 const sub_scope = try block_arena.create(Scope.LocalVal);
11771172 sub_scope.* = .{
11781173 .parent = scope,
1179 .gen_zir = scope.getGenZir(),
1174 .gen_zir = gz,
11801175 .name = ident_name,
11811176 .inst = init_inst,
1177 .src = gz.nodeSrcLoc(node),
11821178 };
11831179 return &sub_scope.base;
11841180 }
......@@ -1207,7 +1203,7 @@ fn varDecl(
12071203 }
12081204 const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope };
12091205 const init_inst = try expr(mod, &init_scope.base, init_result_loc, var_decl.ast.init_node);
1210 const parent_zir = &scope.getGenZir().instructions;
1206 const parent_zir = &gz.instructions;
12111207 if (init_scope.rvalue_rl_count == 1) {
12121208 // Result location pointer not used. We don't need an alloc for this
12131209 // const local, and type inference becomes trivial.
......@@ -1231,7 +1227,7 @@ fn varDecl(
12311227 const sub_scope = try block_arena.create(Scope.LocalVal);
12321228 sub_scope.* = .{
12331229 .parent = scope,
1234 .gen_zir = scope.getGenZir(),
1230 .gen_zir = gz,
12351231 .name = ident_name,
12361232 .inst = casted_init,
12371233 };
......@@ -1258,7 +1254,7 @@ fn varDecl(
12581254 const sub_scope = try block_arena.create(Scope.LocalPtr);
12591255 sub_scope.* = .{
12601256 .parent = scope,
1261 .gen_zir = scope.getGenZir(),
1257 .gen_zir = gz,
12621258 .name = ident_name,
12631259 .ptr = init_scope.rl_ptr.?,
12641260 };
......@@ -1285,9 +1281,10 @@ fn varDecl(
12851281 const sub_scope = try block_arena.create(Scope.LocalPtr);
12861282 sub_scope.* = .{
12871283 .parent = scope,
1288 .gen_zir = scope.getGenZir(),
1284 .gen_zir = gz,
12891285 .name = ident_name,
12901286 .ptr = var_data.alloc,
1287 .src = gz.nodeSrcLoc(node),
12911288 };
12921289 return &sub_scope.base;
12931290 },
......@@ -2078,10 +2075,10 @@ fn copyBodyWithElidedStoreBlockPtr(body: *zir.Body, scope: Module.Scope.GenZir)
20782075 assert(dst_index == body.instructions.len);
20792076}
20802077
2081fn copyBodyNoEliding(body: *zir.Body, scope: Module.Scope.GenZir) !void {
2082 body.* = .{
2083 .instructions = try scope.arena.dupe(zir.Inst.Ref, scope.instructions.items),
2084 };
2078fn copyBodyNoEliding(block_inst: zir.Inst.Index, gz: Module.Scope.GenZir) !void {
2079 const zir_datas = gz.zir_code.instructions.items(.data);
2080 zir_datas[block_inst].pl_node.payload_index = @intCast(u32, gz.zir_code.extra.items.len);
2081 try gz.zir_code.extra.appendSlice(gz.zir_code.gpa, gz.instructions.items);
20852082}
20862083
20872084fn whileExpr(
......@@ -3515,7 +3512,7 @@ fn suspendExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!zir
35153512 return mod.failWithOwnedErrorMsg(scope, msg);
35163513 }
35173514
3518 var suspend_scope: Scope.GenZIR = .{
3515 var suspend_scope: Scope.GenZir = .{
35193516 .base = .{ .tag = .gen_suspend },
35203517 .parent = scope,
35213518 .decl = scope.ownerDecl().?,
......@@ -3864,7 +3861,10 @@ fn rvalue(
38643861 const src_token = tree.firstToken(src_node);
38653862 return gz.addUnTok(.ref, result, src_token);
38663863 },
3867 .ty => |ty_inst| return gz.addBin(.as, ty_inst, result),
3864 .ty => |ty_inst| return gz.addPlNode(.as_node, src_node, zir.Inst.As{
3865 .dest_type = ty_inst,
3866 .operand = result,
3867 }),
38683868 .ptr => |ptr_inst| {
38693869 _ = try gz.addBin(.store, ptr_inst, result);
38703870 return result;
......@@ -3953,17 +3953,17 @@ fn setBlockResultLoc(block_scope: *Scope.GenZir, parent_rl: ResultLoc) void {
39533953 },
39543954
39553955 .inferred_ptr => |ptr| {
3956 block_scope.rl_ptr = &ptr.base;
3956 block_scope.rl_ptr = ptr;
39573957 block_scope.break_result_loc = .{ .block_ptr = block_scope };
39583958 },
39593959
39603960 .bitcasted_ptr => |ptr| {
3961 block_scope.rl_ptr = &ptr.base;
3961 block_scope.rl_ptr = ptr;
39623962 block_scope.break_result_loc = .{ .block_ptr = block_scope };
39633963 },
39643964
39653965 .block_ptr => |parent_block_scope| {
3966 block_scope.rl_ptr = parent_block_scope.rl_ptr.?;
3966 block_scope.rl_ptr = parent_block_scope.rl_ptr;
39673967 block_scope.break_result_loc = .{ .block_ptr = block_scope };
39683968 },
39693969 }
src/zir.zig+36-4
......@@ -72,7 +72,7 @@ pub const Code = struct {
7272 code: Code,
7373 gpa: *Allocator,
7474 kind: []const u8,
75 decl_name: [*:0]const u8,
75 scope: *Module.Scope,
7676 param_count: usize,
7777 ) !void {
7878 var arena = std.heap.ArenaAllocator.init(gpa);
......@@ -81,11 +81,13 @@ pub const Code = struct {
8181 var writer: Writer = .{
8282 .gpa = gpa,
8383 .arena = &arena.allocator,
84 .scope = scope,
8485 .code = code,
8586 .indent = 4,
8687 .param_count = param_count,
8788 };
8889
90 const decl_name = scope.srcDecl().?.name;
8991 const stderr = std.io.getStdErr().writer();
9092 try stderr.print("ZIR {s} {s} {{\n", .{ kind, decl_name });
9193
......@@ -416,9 +418,12 @@ pub const Inst = struct {
416418 /// error if the indexable object is not indexable.
417419 /// Uses the `un_node` field. The AST node is the for loop node.
418420 indexable_ptr_len,
419 /// Type coercion.
421 /// Type coercion. No source location attached.
420422 /// Uses the `bin` field.
421423 as,
424 /// Type coercion to the function's return type.
425 /// Uses the `pl_node` field. Payload is `As`. AST node could be many things.
426 as_node,
422427 /// Inline assembly. Non-volatile.
423428 /// Uses the `pl_node` union field. Payload is `Asm`. AST node is the assembly node.
424429 @"asm",
......@@ -464,12 +469,14 @@ pub const Inst = struct {
464469 /// Uses the `bin` field.
465470 bool_or,
466471 /// Return a value from a block.
467 /// Uses the `bin` union field: `lhs` is `Ref` to the block, `rhs` is operand.
472 /// Uses the `bin` union field: `lhs` is `Index` to the block (*not* `Ref`!),
473 /// `rhs` is operand.
468474 /// Uses the source information from previous instruction.
469475 @"break",
470476 /// Same as `break` but has source information in the form of a token, and
471477 /// the operand is assumed to be the void value.
472478 /// Uses the `un_tok` union field.
479 /// Note that the block operand is a `Index`, not `Ref`.
473480 break_void_tok,
474481 /// Uses the `node` union field.
475482 breakpoint,
......@@ -543,6 +550,9 @@ pub const Inst = struct {
543550 /// Same as `elem_val` except also stores a source location node.
544551 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
545552 elem_val_node,
553 /// This instruction has been deleted late in the astgen phase. It must
554 /// be ignored, and the corresponding `Data` is undefined.
555 elided,
546556 /// Emits a compile error if the operand is not `void`.
547557 /// Uses the `un_node` field.
548558 ensure_result_used,
......@@ -671,6 +681,9 @@ pub const Inst = struct {
671681 /// Includes a token source location.
672682 /// Uses the `un_tok` union field.
673683 ret_tok,
684 /// Same as `ret_tok` except the operand needs to get coerced to the function's
685 /// return type.
686 ret_coerce,
674687 /// Changes the maximum number of backwards branches that compile-time
675688 /// code execution can use before giving up and making a compile error.
676689 /// Uses the `un_node` union field.
......@@ -704,6 +717,7 @@ pub const Inst = struct {
704717 store,
705718 /// Same as `store` but the type of the value being stored will be used to infer
706719 /// the block type. The LHS is the pointer to store to.
720 /// Uses the `bin` union field.
707721 store_to_block_ptr,
708722 /// Same as `store` but the type of the value being stored will be used to infer
709723 /// the pointer type.
......@@ -854,6 +868,7 @@ pub const Inst = struct {
854868 .array_type_sentinel,
855869 .indexable_ptr_len,
856870 .as,
871 .as_node,
857872 .@"asm",
858873 .asm_volatile,
859874 .bit_and,
......@@ -963,6 +978,7 @@ pub const Inst = struct {
963978 .@"resume",
964979 .@"await",
965980 .nosuspend_await,
981 .elided,
966982 => false,
967983
968984 .@"break",
......@@ -971,6 +987,7 @@ pub const Inst = struct {
971987 .compile_error,
972988 .ret_node,
973989 .ret_tok,
990 .ret_coerce,
974991 .unreachable_unsafe,
975992 .unreachable_safe,
976993 .loop,
......@@ -1242,11 +1259,17 @@ pub const Inst = struct {
12421259 lhs: Ref,
12431260 field_name: Ref,
12441261 };
1262
1263 pub const As = struct {
1264 dest_type: Ref,
1265 operand: Ref,
1266 };
12451267};
12461268
12471269const Writer = struct {
12481270 gpa: *Allocator,
12491271 arena: *Allocator,
1272 scope: *Module.Scope,
12501273 code: Code,
12511274 indent: usize,
12521275 param_count: usize,
......@@ -1325,6 +1348,7 @@ const Writer = struct {
13251348 .is_err_ptr,
13261349 .ref,
13271350 .ret_tok,
1351 .ret_coerce,
13281352 .typeof,
13291353 .optional_type,
13301354 .optional_type_from_ptr_elem,
......@@ -1348,6 +1372,7 @@ const Writer = struct {
13481372 .ptr_type => try self.writePtrType(stream, inst),
13491373 .int => try self.writeInt(stream, inst),
13501374 .str => try self.writeStr(stream, inst),
1375 .elided => try stream.writeAll(")"),
13511376
13521377 .@"asm",
13531378 .asm_volatile,
......@@ -1374,6 +1399,7 @@ const Writer = struct {
13741399 .slice_sentinel,
13751400 .typeof_peer,
13761401 .suspend_block,
1402 .as_node,
13771403 => try self.writePlNode(stream, inst),
13781404
13791405 .breakpoint,
......@@ -1641,6 +1667,12 @@ const Writer = struct {
16411667 }
16421668
16431669 fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void {
1644 try stream.print("TODOsrc({s})", .{@tagName(src)});
1670 const tree = self.scope.tree();
1671 const src_loc = src.toSrcLoc(self.scope);
1672 const abs_byte_off = try src_loc.byteOffset();
1673 const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off);
1674 try stream.print("{s}:{d}:{d}", .{
1675 @tagName(src), delta_line.line + 1, delta_line.column + 1,
1676 });
16451677 }
16461678};