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 @@...@@ -1,9 +1,6 @@
1this is my WIP branch scratch pad, to be deleted before merging into master1this is my WIP branch scratch pad, to be deleted before merging into master
22
3Merge TODO list:3Merge TODO list:
4 * fix discrepancy between TZIR wanting src: usize (byte offset) and Sema
5 now providing LazySrcLoc
6 * fix compile errors
7 * don't have an explicit dbg_stmt zir instruction - instead merge it with4 * don't have an explicit dbg_stmt zir instruction - instead merge it with
8 var decl and assignment instructions, etc.5 var decl and assignment instructions, etc.
9 - make it set sema.src where appropriate6 - make it set sema.src where appropriate
...@@ -13,6 +10,7 @@ Merge TODO list:...@@ -13,6 +10,7 @@ Merge TODO list:
13 * finish implementing SrcLoc byteOffset function10 * finish implementing SrcLoc byteOffset function
14 * audit Module.zig for use of token_starts - it should only be when11 * audit Module.zig for use of token_starts - it should only be when
15 resolving LazySrcLoc12 resolving LazySrcLoc
13 * audit astgen.zig for use of token_starts - I think there should be no uses
16 * audit all the .unneeded src locations14 * audit all the .unneeded src locations
17 * audit the calls in codegen toSrcLocWithDecl specifically if there is inlined function15 * audit the calls in codegen toSrcLocWithDecl specifically if there is inlined function
18 calls from other files.16 calls from other files.
...@@ -29,20 +27,6 @@ Performance optimizations to look into:...@@ -29,20 +27,6 @@ Performance optimizations to look into:
29 - Look into this for enum literals too27 - Look into this for enum literals too
30 * make ret_type and ret_ptr instructions be implied indexes; no need to have28 * make ret_type and ret_ptr instructions be implied indexes; no need to have
31 tags associated with them.29 tags associated with them.
3230 * use a smaller encoding for the auto generated return void at the end of
3331 function ZIR.
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
4832
lib/std/zig/parse.zig+20-5
...@@ -139,6 +139,16 @@ const Parser = struct {...@@ -139,6 +139,16 @@ const Parser = struct {
139 return result;139 return result;
140 }140 }
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
142 fn addExtra(p: *Parser, extra: anytype) Allocator.Error!Node.Index {152 fn addExtra(p: *Parser, extra: anytype) Allocator.Error!Node.Index {
143 const fields = std.meta.fields(@TypeOf(extra));153 const fields = std.meta.fields(@TypeOf(extra));
144 try p.extra_data.ensureCapacity(p.gpa, p.extra_data.items.len + fields.len);154 try p.extra_data.ensureCapacity(p.gpa, p.extra_data.items.len + fields.len);
...@@ -554,9 +564,10 @@ const Parser = struct {...@@ -554,9 +564,10 @@ const Parser = struct {
554 return fn_proto;564 return fn_proto;
555 },565 },
556 .l_brace => {566 .l_brace => {
567 const fn_decl_index = try p.reserveNode();
557 const body_block = try p.parseBlock();568 const body_block = try p.parseBlock();
558 assert(body_block != 0);569 assert(body_block != 0);
559 return p.addNode(.{570 return p.setNode(fn_decl_index, .{
560 .tag = .fn_decl,571 .tag = .fn_decl,
561 .main_token = p.nodes.items(.main_token)[fn_proto],572 .main_token = p.nodes.items(.main_token)[fn_proto],
562 .data = .{573 .data = .{
...@@ -634,6 +645,10 @@ const Parser = struct {...@@ -634,6 +645,10 @@ const Parser = struct {
634 /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? CallConv? EXCLAMATIONMARK? (Keyword_anytype / TypeExpr)645 /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? CallConv? EXCLAMATIONMARK? (Keyword_anytype / TypeExpr)
635 fn parseFnProto(p: *Parser) !Node.Index {646 fn parseFnProto(p: *Parser) !Node.Index {
636 const fn_token = p.eatToken(.keyword_fn) orelse return null_node;647 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
637 _ = p.eatToken(.identifier);652 _ = p.eatToken(.identifier);
638 const params = try p.parseParamDeclList();653 const params = try p.parseParamDeclList();
639 defer params.deinit(p.gpa);654 defer params.deinit(p.gpa);
...@@ -651,7 +666,7 @@ const Parser = struct {...@@ -651,7 +666,7 @@ const Parser = struct {
651666
652 if (align_expr == 0 and section_expr == 0 and callconv_expr == 0) {667 if (align_expr == 0 and section_expr == 0 and callconv_expr == 0) {
653 switch (params) {668 switch (params) {
654 .zero_or_one => |param| return p.addNode(.{669 .zero_or_one => |param| return p.setNode(fn_proto_index, .{
655 .tag = .fn_proto_simple,670 .tag = .fn_proto_simple,
656 .main_token = fn_token,671 .main_token = fn_token,
657 .data = .{672 .data = .{
...@@ -661,7 +676,7 @@ const Parser = struct {...@@ -661,7 +676,7 @@ const Parser = struct {
661 }),676 }),
662 .multi => |list| {677 .multi => |list| {
663 const span = try p.listToSpan(list);678 const span = try p.listToSpan(list);
664 return p.addNode(.{679 return p.setNode(fn_proto_index, .{
665 .tag = .fn_proto_multi,680 .tag = .fn_proto_multi,
666 .main_token = fn_token,681 .main_token = fn_token,
667 .data = .{682 .data = .{
...@@ -676,7 +691,7 @@ const Parser = struct {...@@ -676,7 +691,7 @@ const Parser = struct {
676 }691 }
677 }692 }
678 switch (params) {693 switch (params) {
679 .zero_or_one => |param| return p.addNode(.{694 .zero_or_one => |param| return p.setNode(fn_proto_index, .{
680 .tag = .fn_proto_one,695 .tag = .fn_proto_one,
681 .main_token = fn_token,696 .main_token = fn_token,
682 .data = .{697 .data = .{
...@@ -691,7 +706,7 @@ const Parser = struct {...@@ -691,7 +706,7 @@ const Parser = struct {
691 }),706 }),
692 .multi => |list| {707 .multi => |list| {
693 const span = try p.listToSpan(list);708 const span = try p.listToSpan(list);
694 return p.addNode(.{709 return p.setNode(fn_proto_index, .{
695 .tag = .fn_proto,710 .tag = .fn_proto,
696 .main_token = fn_token,711 .main_token = fn_token,
697 .data = .{712 .data = .{
src/Compilation.zig+2-2
...@@ -317,7 +317,7 @@ pub const AllErrors = struct {...@@ -317,7 +317,7 @@ pub const AllErrors = struct {
317 for (notes) |*note, i| {317 for (notes) |*note, i| {
318 const module_note = module_err_msg.notes[i];318 const module_note = module_err_msg.notes[i];
319 const source = try module_note.src_loc.fileScope().getSource(module);319 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();
321 const loc = std.zig.findLineColumn(source, byte_offset);321 const loc = std.zig.findLineColumn(source, byte_offset);
322 const sub_file_path = module_note.src_loc.fileScope().sub_file_path;322 const sub_file_path = module_note.src_loc.fileScope().sub_file_path;
323 note.* = .{323 note.* = .{
...@@ -331,7 +331,7 @@ pub const AllErrors = struct {...@@ -331,7 +331,7 @@ pub const AllErrors = struct {
331 };331 };
332 }332 }
333 const source = try module_err_msg.src_loc.fileScope().getSource(module);333 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();
335 const loc = std.zig.findLineColumn(source, byte_offset);335 const loc = std.zig.findLineColumn(source, byte_offset);
336 const sub_file_path = module_err_msg.src_loc.fileScope().sub_file_path;336 const sub_file_path = module_err_msg.src_loc.fileScope().sub_file_path;
337 try errors.append(.{337 try errors.append(.{
src/Module.zig+230-12
...@@ -241,6 +241,10 @@ pub const Decl = struct {...@@ -241,6 +241,10 @@ pub const Decl = struct {
241 return .{ .token_offset = token_index - decl.srcToken() };241 return .{ .token_offset = token_index - decl.srcToken() };
242 }242 }
243243
244 pub fn nodeSrcLoc(decl: *Decl, node_index: ast.Node.Index) LazySrcLoc {
245 return .{ .node_offset = node_index - decl.srcNode() };
246 }
247
244 pub fn srcLoc(decl: *Decl) SrcLoc {248 pub fn srcLoc(decl: *Decl) SrcLoc {
245 return .{249 return .{
246 .container = .{ .decl = decl },250 .container = .{ .decl = decl },
...@@ -1003,10 +1007,14 @@ pub const Scope = struct {...@@ -1003,10 +1007,14 @@ pub const Scope = struct {
1003 };1007 };
1004 }1008 }
10051009
1006 pub fn tokSrcLoc(gz: *GenZir, token_index: ast.TokenIndex) LazySrcLoc {1010 pub fn tokSrcLoc(gz: GenZir, token_index: ast.TokenIndex) LazySrcLoc {
1007 return gz.zir_code.decl.tokSrcLoc(token_index);1011 return gz.zir_code.decl.tokSrcLoc(token_index);
1008 }1012 }
10091013
1014 pub fn nodeSrcLoc(gz: GenZir, node_index: ast.Node.Index) LazySrcLoc {
1015 return gz.zir_code.decl.nodeSrcLoc(node_index);
1016 }
1017
1010 pub fn addFnTypeCc(gz: *GenZir, tag: zir.Inst.Tag, args: struct {1018 pub fn addFnTypeCc(gz: *GenZir, tag: zir.Inst.Tag, args: struct {
1011 param_types: []const zir.Inst.Ref,1019 param_types: []const zir.Inst.Ref,
1012 ret_ty: zir.Inst.Ref,1020 ret_ty: zir.Inst.Ref,
...@@ -1092,6 +1100,30 @@ pub const Scope = struct {...@@ -1092,6 +1100,30 @@ pub const Scope = struct {
1092 });1100 });
1093 }1101 }
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
1095 pub fn addUnTok(1127 pub fn addUnTok(
1096 gz: *GenZir,1128 gz: *GenZir,
1097 tag: zir.Inst.Tag,1129 tag: zir.Inst.Tag,
...@@ -1165,6 +1197,21 @@ pub const Scope = struct {...@@ -1165,6 +1197,21 @@ pub const Scope = struct {
1165 });1197 });
1166 }1198 }
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
1168 fn add(gz: *GenZir, inst: zir.Inst) !zir.Inst.Ref {1215 fn add(gz: *GenZir, inst: zir.Inst) !zir.Inst.Ref {
1169 const gpa = gz.zir_code.gpa;1216 const gpa = gz.zir_code.gpa;
1170 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);1217 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
...@@ -1188,6 +1235,8 @@ pub const Scope = struct {...@@ -1188,6 +1235,8 @@ pub const Scope = struct {
1188 gen_zir: *GenZir,1235 gen_zir: *GenZir,
1189 name: []const u8,1236 name: []const u8,
1190 inst: zir.Inst.Index,1237 inst: zir.Inst.Index,
1238 /// Source location of the corresponding variable declaration.
1239 src: LazySrcLoc,
1191 };1240 };
11921241
1193 /// This could be a `const` or `var` local. It has a pointer instead of a value.1242 /// This could be a `const` or `var` local. It has a pointer instead of a value.
...@@ -1201,6 +1250,8 @@ pub const Scope = struct {...@@ -1201,6 +1250,8 @@ pub const Scope = struct {
1201 gen_zir: *GenZir,1250 gen_zir: *GenZir,
1202 name: []const u8,1251 name: []const u8,
1203 ptr: zir.Inst.Index,1252 ptr: zir.Inst.Index,
1253 /// Source location of the corresponding variable declaration.
1254 src: LazySrcLoc,
1204 };1255 };
12051256
1206 pub const Nosuspend = struct {1257 pub const Nosuspend = struct {
...@@ -1246,6 +1297,169 @@ pub const WipZirCode = struct {...@@ -1246,6 +1297,169 @@ pub const WipZirCode = struct {
1246 return result;1297 return result;
1247 }1298 }
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
1249 pub fn deinit(wzc: *WipZirCode) void {1463 pub fn deinit(wzc: *WipZirCode) void {
1250 wzc.instructions.deinit(wzc.gpa);1464 wzc.instructions.deinit(wzc.gpa);
1251 wzc.extra.deinit(wzc.gpa);1465 wzc.extra.deinit(wzc.gpa);
...@@ -1348,7 +1562,7 @@ pub const SrcLoc = struct {...@@ -1348,7 +1562,7 @@ pub const SrcLoc = struct {
1348 };1562 };
1349 }1563 }
13501564
1351 pub fn byteOffset(src_loc: SrcLoc, mod: *Module) !u32 {1565 pub fn byteOffset(src_loc: SrcLoc) !u32 {
1352 switch (src_loc.lazy) {1566 switch (src_loc.lazy) {
1353 .unneeded => unreachable,1567 .unneeded => unreachable,
1354 .todo => unreachable,1568 .todo => unreachable,
...@@ -1373,14 +1587,14 @@ pub const SrcLoc = struct {...@@ -1373,14 +1587,14 @@ pub const SrcLoc = struct {
1373 .token_offset => |tok_off| {1587 .token_offset => |tok_off| {
1374 const decl = src_loc.container.decl;1588 const decl = src_loc.container.decl;
1375 const tok_index = decl.srcToken() + tok_off;1589 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();
1377 const token_starts = tree.tokens.items(.start);1591 const token_starts = tree.tokens.items(.start);
1378 return token_starts[tok_index];1592 return token_starts[tok_index];
1379 },1593 },
1380 .node_offset => |node_off| {1594 .node_offset => |node_off| {
1381 const decl = src_loc.container.decl;1595 const decl = src_loc.container.decl;
1382 const node_index = decl.srcNode() + node_off;1596 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();
1384 const tok_index = tree.firstToken(node_index);1598 const tok_index = tree.firstToken(node_index);
1385 const token_starts = tree.tokens.items(.start);1599 const token_starts = tree.tokens.items(.start);
1386 return token_starts[tok_index];1600 return token_starts[tok_index];
...@@ -1826,7 +2040,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {...@@ -1826,7 +2040,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
18262040
1827 const code = try gen_scope.finish();2041 const code = try gen_scope.finish();
1828 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {2042 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 {};
1830 }2044 }
1831 break :blk code;2045 break :blk code;
1832 };2046 };
...@@ -2047,7 +2261,7 @@ fn astgenAndSemaFn(...@@ -2047,7 +2261,7 @@ fn astgenAndSemaFn(
20472261
2048 const fn_type_code = try fn_type_scope.finish();2262 const fn_type_code = try fn_type_scope.finish();
2049 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {2263 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 {};
2051 }2265 }
20522266
2053 var fn_type_sema: Sema = .{2267 var fn_type_sema: Sema = .{
...@@ -2146,6 +2360,7 @@ fn astgenAndSemaFn(...@@ -2146,6 +2360,7 @@ fn astgenAndSemaFn(
2146 .name = param_name,2360 .name = param_name,
2147 // Implicit const list first, then implicit arg list.2361 // Implicit const list first, then implicit arg list.
2148 .inst = @intCast(u32, zir.const_inst_list.len + i),2362 .inst = @intCast(u32, zir.const_inst_list.len + i),
2363 .src = decl.tokSrcLoc(name_token),
2149 };2364 };
2150 params_scope = &sub_scope.base;2365 params_scope = &sub_scope.base;
21512366
...@@ -2164,13 +2379,16 @@ fn astgenAndSemaFn(...@@ -2164,13 +2379,16 @@ fn astgenAndSemaFn(
2164 !wip_zir_code.instructions.items(.tag)[gen_scope.instructions.items.len - 1]2379 !wip_zir_code.instructions.items(.tag)[gen_scope.instructions.items.len - 1]
2165 .isNoReturn())2380 .isNoReturn())
2166 {2381 {
2167 const void_operand = @enumToInt(zir.Const.void_value);2382 // astgen uses result location semantics to coerce return operands.
2168 _ = try gen_scope.addUnTok(.ret_tok, void_operand, tree.lastToken(body_node));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));
2169 }2387 }
21702388
2171 const code = try gen_scope.finish();2389 const code = try gen_scope.finish();
2172 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {2390 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 {};
2174 }2392 }
21752393
2176 break :blk code;2394 break :blk code;
...@@ -2347,7 +2565,7 @@ fn astgenAndSemaVarDecl(...@@ -2347,7 +2565,7 @@ fn astgenAndSemaVarDecl(
2347 );2565 );
2348 const code = try gen_scope.finish();2566 const code = try gen_scope.finish();
2349 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {2567 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 {};
2351 }2569 }
23522570
2353 var sema: Sema = .{2571 var sema: Sema = .{
...@@ -2409,7 +2627,7 @@ fn astgenAndSemaVarDecl(...@@ -2409,7 +2627,7 @@ fn astgenAndSemaVarDecl(
2409 const var_type = try astgen.typeExpr(mod, &type_scope.base, var_decl.ast.type_node);2627 const var_type = try astgen.typeExpr(mod, &type_scope.base, var_decl.ast.type_node);
2410 const code = try type_scope.finish();2628 const code = try type_scope.finish();
2411 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {2629 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 {};
2413 }2631 }
24142632
2415 var sema: Sema = .{2633 var sema: Sema = .{
...@@ -3475,7 +3693,7 @@ pub fn failNode(...@@ -3475,7 +3693,7 @@ pub fn failNode(
3475 args: anytype,3693 args: anytype,
3476) InnerError {3694) InnerError {
3477 const decl_node = scope.srcDecl().?.srcNode();3695 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 };
3479 return mod.fail(scope, src, format, args);3697 return mod.fail(scope, src, format, args);
3480}3698}
34813699
src/Sema.zig+50-10
...@@ -108,6 +108,7 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde...@@ -108,6 +108,7 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde
108 .dbg_stmt_node => try sema.zirDbgStmtNode(block, zir_inst),108 .dbg_stmt_node => try sema.zirDbgStmtNode(block, zir_inst),
109 .decl_ref => try sema.zirDeclRef(block, zir_inst),109 .decl_ref => try sema.zirDeclRef(block, zir_inst),
110 .decl_val => try sema.zirDeclVal(block, zir_inst),110 .decl_val => try sema.zirDeclVal(block, zir_inst),
111 .elided => continue,
111 .ensure_result_used => try sema.zirEnsureResultUsed(block, zir_inst),112 .ensure_result_used => try sema.zirEnsureResultUsed(block, zir_inst),
112 .ensure_result_non_error => try sema.zirEnsureResultNonError(block, zir_inst),113 .ensure_result_non_error => try sema.zirEnsureResultNonError(block, zir_inst),
113 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, zir_inst),114 .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...@@ -133,11 +134,13 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde
133 .field_val_named => try sema.zirFieldValNamed(block, zir_inst),134 .field_val_named => try sema.zirFieldValNamed(block, zir_inst),
134 .deref_node => try sema.zirDerefNode(block, zir_inst),135 .deref_node => try sema.zirDerefNode(block, zir_inst),
135 .as => try sema.zirAs(block, zir_inst),136 .as => try sema.zirAs(block, zir_inst),
137 .as_node => try sema.zirAsNode(block, zir_inst),
136 .@"asm" => try sema.zirAsm(block, zir_inst, false),138 .@"asm" => try sema.zirAsm(block, zir_inst, false),
137 .asm_volatile => try sema.zirAsm(block, zir_inst, true),139 .asm_volatile => try sema.zirAsm(block, zir_inst, true),
138 .unreachable_safe => try sema.zirUnreachable(block, zir_inst, true),140 .unreachable_safe => try sema.zirUnreachable(block, zir_inst, true),
139 .unreachable_unsafe => try sema.zirUnreachable(block, zir_inst, false),141 .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),
141 .ret_node => try sema.zirRetNode(block, zir_inst),144 .ret_node => try sema.zirRetNode(block, zir_inst),
142 .fn_type => try sema.zirFnType(block, zir_inst, false),145 .fn_type => try sema.zirFnType(block, zir_inst, false),
143 .fn_type_cc => try sema.zirFnTypeCc(block, zir_inst, false),146 .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...@@ -1004,7 +1007,7 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE
1004 const src_node = sema.code.instructions.items(.data)[inst].node;1007 const src_node = sema.code.instructions.items(.data)[inst].node;
1005 const src: LazySrcLoc = .{ .node_offset = src_node };1008 const src: LazySrcLoc = .{ .node_offset = src_node };
1006 const src_loc = src.toSrcLoc(&block.base);1009 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();
1008 return block.addDbgStmt(src, abs_byte_off);1011 return block.addDbgStmt(src, abs_byte_off);
1009}1012}
10101013
...@@ -1767,9 +1770,29 @@ fn zirAs(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Ins...@@ -1767,9 +1770,29 @@ fn zirAs(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Ins
1767 defer tracy.end();1770 defer tracy.end();
17681771
1769 const bin_inst = sema.code.instructions.items(.data)[inst].bin;1772 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1770 const dest_type = try sema.resolveType(block, .todo, bin_inst.lhs);1773 return sema.analyzeAs(block, .unneeded, bin_inst.lhs, bin_inst.rhs);
1771 const tzir_inst = try sema.resolveInst(bin_inst.rhs);1774}
1772 return sema.coerce(block, dest_type, tzir_inst, .todo);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);
1773}1796}
17741797
1775fn zirPtrtoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {1798fn zirPtrtoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
...@@ -2850,7 +2873,12 @@ fn zirUnreachable(...@@ -2850,7 +2873,12 @@ fn zirUnreachable(
2850 }2873 }
2851}2874}
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 {
2854 const tracy = trace(@src());2882 const tracy = trace(@src());
2855 defer tracy.end();2883 defer tracy.end();
28562884
...@@ -2858,7 +2886,7 @@ fn zirRetTok(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!...@@ -2858,7 +2886,7 @@ fn zirRetTok(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!
2858 const operand = try sema.resolveInst(inst_data.operand);2886 const operand = try sema.resolveInst(inst_data.operand);
2859 const src = inst_data.src();2887 const src = inst_data.src();
28602888
2861 return sema.analyzeRet(block, operand, src);2889 return sema.analyzeRet(block, operand, src, need_coercion);
2862}2890}
28632891
2864fn zirRetNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {2892fn 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...@@ -2869,10 +2897,16 @@ fn zirRetNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
2869 const operand = try sema.resolveInst(inst_data.operand);2897 const operand = try sema.resolveInst(inst_data.operand);
2870 const src = inst_data.src();2898 const src = inst_data.src();
28712899
2872 return sema.analyzeRet(block, operand, src);2900 return sema.analyzeRet(block, operand, src, false);
2873}2901}
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 {
2876 if (block.inlining) |inlining| {2910 if (block.inlining) |inlining| {
2877 // We are inlining a function call; rewrite the `ret` as a `break`.2911 // We are inlining a function call; rewrite the `ret` as a `break`.
2878 try inlining.merges.results.append(sema.gpa, operand);2912 try inlining.merges.results.append(sema.gpa, operand);
...@@ -2880,7 +2914,13 @@ fn analyzeRet(sema: *Sema, block: *Scope.Block, operand: *Inst, src: LazySrcLoc)...@@ -2880,7 +2914,13 @@ fn analyzeRet(sema: *Sema, block: *Scope.Block, operand: *Inst, src: LazySrcLoc)
2880 return &br.base;2914 return &br.base;
2881 }2915 }
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 }
2884 return block.addUnOp(src, Type.initTag(.noreturn), .ret, operand);2924 return block.addUnOp(src, Type.initTag(.noreturn), .ret, operand);
2885}2925}
28862926
src/astgen.zig+57-57
...@@ -497,7 +497,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In...@@ -497,7 +497,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
497 }497 }
498 },498 },
499 .block_two, .block_two_semicolon => {499 .block_two, .block_two_semicolon => {
500 if (true) @panic("TODO update for zir-memory-layout");
501 const statements = [2]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs };500 const statements = [2]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs };
502 if (node_datas[node].lhs == 0) {501 if (node_datas[node].lhs == 0) {
503 return blockExpr(mod, scope, rl, node, statements[0..0]);502 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...@@ -508,7 +507,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
508 }507 }
509 },508 },
510 .block, .block_semicolon => {509 .block, .block_semicolon => {
511 if (true) @panic("TODO update for zir-memory-layout");
512 const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];510 const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];
513 return blockExpr(mod, scope, rl, node, statements);511 return blockExpr(mod, scope, rl, node, statements);
514 },512 },
...@@ -808,7 +806,7 @@ fn breakExpr(...@@ -808,7 +806,7 @@ fn breakExpr(
808 },806 },
809 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,807 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
810 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,808 .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,
812 .gen_nosuspend => scope = scope.cast(Scope.Nosuspend).?.parent,810 .gen_nosuspend => scope = scope.cast(Scope.Nosuspend).?.parent,
813 else => if (break_label != 0) {811 else => if (break_label != 0) {
814 const label_name = try mod.identifierTokenString(parent_scope, break_label);812 const label_name = try mod.identifierTokenString(parent_scope, break_label);
...@@ -864,7 +862,7 @@ fn continueExpr(...@@ -864,7 +862,7 @@ fn continueExpr(
864 },862 },
865 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,863 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
866 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,864 .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,
868 .gen_nosuspend => scope = scope.cast(Scope.Nosuspend).?.parent,866 .gen_nosuspend => scope = scope.cast(Scope.Nosuspend).?.parent,
869 else => if (break_label != 0) {867 else => if (break_label != 0) {
870 const label_name = try mod.identifierTokenString(parent_scope, break_label);868 const label_name = try mod.identifierTokenString(parent_scope, break_label);
...@@ -939,7 +937,7 @@ fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIn...@@ -939,7 +937,7 @@ fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIn
939 },937 },
940 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,938 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
941 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,939 .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,
943 .gen_nosuspend => scope = scope.cast(Scope.Nosuspend).?.parent,941 .gen_nosuspend => scope = scope.cast(Scope.Nosuspend).?.parent,
944 else => return,942 else => return,
945 }943 }
...@@ -971,25 +969,14 @@ fn labeledBlockExpr(...@@ -971,25 +969,14 @@ fn labeledBlockExpr(
971969
972 try checkLabelRedefinition(mod, parent_scope, label_token);970 try checkLabelRedefinition(mod, parent_scope, label_token);
973971
974 // Create the Block ZIR instruction so that we can put it into the GenZir struct972 // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct
975 // so that break statements can reference it.973 // so that break statements can reference it.
976 const gen_zir = parent_scope.getGenZir();974 const gz = parent_scope.getGenZir();
977 const block_inst = try gen_zir.arena.create(zir.Inst.Block);975 const block_inst = try gz.addBlock(zir_tag, block_node);
978 block_inst.* = .{
979 .base = .{
980 .tag = zir_tag,
981 .src = src,
982 },
983 .positionals = .{
984 .body = .{ .instructions = undefined },
985 },
986 .kw_args = .{},
987 };
988976
989 var block_scope: Scope.GenZir = .{977 var block_scope: Scope.GenZir = .{
990 .parent = parent_scope,978 .parent = parent_scope,
991 .decl = parent_scope.ownerDecl().?,979 .zir_code = gz.zir_code,
992 .arena = gen_zir.arena,
993 .force_comptime = parent_scope.isComptime(),980 .force_comptime = parent_scope.isComptime(),
994 .instructions = .{},981 .instructions = .{},
995 // TODO @as here is working around a stage1 miscompilation bug :(982 // TODO @as here is working around a stage1 miscompilation bug :(
...@@ -1009,35 +996,40 @@ fn labeledBlockExpr(...@@ -1009,35 +996,40 @@ fn labeledBlockExpr(
1009 return mod.failTok(parent_scope, label_token, "unused block label", .{});996 return mod.failTok(parent_scope, label_token, "unused block label", .{});
1010 }997 }
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
1014 const strat = rlStrategy(rl, &block_scope);1004 const strat = rlStrategy(rl, &block_scope);
1015 switch (strat.tag) {1005 switch (strat.tag) {
1016 .break_void => {1006 .break_void => {
1017 // The code took advantage of the result location as a pointer.1007 // 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.
1019 for (block_scope.labeled_breaks.items) |br| {1009 for (block_scope.labeled_breaks.items) |br| {
1020 br.base.tag = .break_void;1010 zir_datas[br].bin.rhs = 0;
1021 }1011 }
1022 // TODO technically not needed since we changed the tag to break_void but1012 // TODO technically not needed since we changed the tag to break_void but
1023 // would be better still to elide the ones that are in this list.1013 // 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;
1027 },1017 },
1028 .break_operand => {1018 .break_operand => {
1029 // All break operands are values that did not use the result location pointer.1019 // All break operands are values that did not use the result location pointer.
1030 if (strat.elide_store_to_block_ptr_instructions) {1020 if (strat.elide_store_to_block_ptr_instructions) {
1031 for (block_scope.labeled_store_to_block_ptr_list.items) |inst| {1021 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;
1033 }1024 }
1034 // TODO technically not needed since we changed the tag to void_value but1025 // TODO technically not needed since we changed the tag to elided but
1035 // would be better still to elide the ones that are in this list.1026 // would be better still to elide the ones that are in this list.
1036 }1027 }
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;
1038 switch (rl) {1030 switch (rl) {
1039 .ref => return &block_inst.base,1031 .ref => return block_ref,
1040 else => return rvalue(mod, parent_scope, rl, &block_inst.base),1032 else => return rvalue(mod, parent_scope, rl, block_ref, block_node),
1041 }1033 }
1042 },1034 },
1043 }1035 }
...@@ -1057,15 +1049,16 @@ fn blockExprStmts(...@@ -1057,15 +1049,16 @@ fn blockExprStmts(
1057 var block_arena = std.heap.ArenaAllocator.init(mod.gpa);1049 var block_arena = std.heap.ArenaAllocator.init(mod.gpa);
1058 defer block_arena.deinit();1050 defer block_arena.deinit();
10591051
1052 const gz = parent_scope.getGenZir();
1053
1060 var scope = parent_scope;1054 var scope = parent_scope;
1061 for (statements) |statement| {1055 for (statements) |statement| {
1062 const src = token_starts[tree.firstToken(statement)];1056 _ = try gz.addNode(.dbg_stmt_node, statement);
1063 _ = try addZIRNoOp(mod, scope, src, .dbg_stmt);
1064 switch (node_tags[statement]) {1057 switch (node_tags[statement]) {
1065 .global_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.globalVarDecl(statement)),1058 .global_var_decl => scope = try varDecl(mod, scope, statement, &block_arena.allocator, tree.globalVarDecl(statement)),
1066 .local_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.localVarDecl(statement)),1059 .local_var_decl => scope = try varDecl(mod, scope, statement, &block_arena.allocator, tree.localVarDecl(statement)),
1067 .simple_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.simpleVarDecl(statement)),1060 .simple_var_decl => scope = try varDecl(mod, scope, statement, &block_arena.allocator, tree.simpleVarDecl(statement)),
1068 .aligned_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.alignedVarDecl(statement)),1061 .aligned_var_decl => scope = try varDecl(mod, scope, statement, &block_arena.allocator, tree.alignedVarDecl(statement)),
10691062
1070 .assign => try assign(mod, scope, statement),1063 .assign => try assign(mod, scope, statement),
1071 .assign_bit_and => try assignOp(mod, scope, statement, .bit_and),1064 .assign_bit_and => try assignOp(mod, scope, statement, .bit_and),
...@@ -1084,8 +1077,8 @@ fn blockExprStmts(...@@ -1084,8 +1077,8 @@ fn blockExprStmts(
10841077
1085 else => {1078 else => {
1086 const possibly_unused_result = try expr(mod, scope, .none, statement);1079 const possibly_unused_result = try expr(mod, scope, .none, statement);
1087 if (!possibly_unused_result.tag.isNoReturn()) {1080 if (!gz.zir_code.isVoidOrNoReturn(possibly_unused_result)) {
1088 _ = try addZIRUnOp(mod, scope, src, .ensure_result_used, possibly_unused_result);1081 _ = try gz.addUnNode(.ensure_result_used, possibly_unused_result, statement);
1089 }1082 }
1090 },1083 },
1091 }1084 }
...@@ -1095,22 +1088,24 @@ fn blockExprStmts(...@@ -1095,22 +1088,24 @@ fn blockExprStmts(
1095fn varDecl(1088fn varDecl(
1096 mod: *Module,1089 mod: *Module,
1097 scope: *Scope,1090 scope: *Scope,
1091 node: ast.Node.Index,
1098 block_arena: *Allocator,1092 block_arena: *Allocator,
1099 var_decl: ast.full.VarDecl,1093 var_decl: ast.full.VarDecl,
1100) InnerError!*Scope {1094) InnerError!*Scope {
1095 if (true) @panic("TODO update for zir-memory-layout");
1096
1101 if (var_decl.comptime_token) |comptime_token| {1097 if (var_decl.comptime_token) |comptime_token| {
1102 return mod.failTok(scope, comptime_token, "TODO implement comptime locals", .{});1098 return mod.failTok(scope, comptime_token, "TODO implement comptime locals", .{});
1103 }1099 }
1104 if (var_decl.ast.align_node != 0) {1100 if (var_decl.ast.align_node != 0) {
1105 return mod.failNode(scope, var_decl.ast.align_node, "TODO implement alignment on locals", .{});1101 return mod.failNode(scope, var_decl.ast.align_node, "TODO implement alignment on locals", .{});
1106 }1102 }
1103 const gz = scope.getGenZir();
1107 const tree = scope.tree();1104 const tree = scope.tree();
1108 const main_tokens = tree.nodes.items(.main_token);
1109 const token_starts = tree.tokens.items(.start);
1110 const token_tags = tree.tokens.items(.tag);1105 const token_tags = tree.tokens.items(.tag);
11111106
1112 const name_token = var_decl.ast.mut_token + 1;1107 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);
1114 const ident_name = try mod.identifierTokenString(scope, name_token);1109 const ident_name = try mod.identifierTokenString(scope, name_token);
11151110
1116 // Local variables shadowing detection, including function parameters.1111 // Local variables shadowing detection, including function parameters.
...@@ -1125,7 +1120,7 @@ fn varDecl(...@@ -1125,7 +1120,7 @@ fn varDecl(
1125 ident_name,1120 ident_name,
1126 });1121 });
1127 errdefer msg.destroy(mod.gpa);1122 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", .{});
1129 break :msg msg;1124 break :msg msg;
1130 };1125 };
1131 return mod.failWithOwnedErrorMsg(scope, msg);1126 return mod.failWithOwnedErrorMsg(scope, msg);
...@@ -1140,7 +1135,7 @@ fn varDecl(...@@ -1140,7 +1135,7 @@ fn varDecl(
1140 ident_name,1135 ident_name,
1141 });1136 });
1142 errdefer msg.destroy(mod.gpa);1137 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", .{});
1144 break :msg msg;1139 break :msg msg;
1145 };1140 };
1146 return mod.failWithOwnedErrorMsg(scope, msg);1141 return mod.failWithOwnedErrorMsg(scope, msg);
...@@ -1176,9 +1171,10 @@ fn varDecl(...@@ -1176,9 +1171,10 @@ fn varDecl(
1176 const sub_scope = try block_arena.create(Scope.LocalVal);1171 const sub_scope = try block_arena.create(Scope.LocalVal);
1177 sub_scope.* = .{1172 sub_scope.* = .{
1178 .parent = scope,1173 .parent = scope,
1179 .gen_zir = scope.getGenZir(),1174 .gen_zir = gz,
1180 .name = ident_name,1175 .name = ident_name,
1181 .inst = init_inst,1176 .inst = init_inst,
1177 .src = gz.nodeSrcLoc(node),
1182 };1178 };
1183 return &sub_scope.base;1179 return &sub_scope.base;
1184 }1180 }
...@@ -1207,7 +1203,7 @@ fn varDecl(...@@ -1207,7 +1203,7 @@ fn varDecl(
1207 }1203 }
1208 const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope };1204 const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope };
1209 const init_inst = try expr(mod, &init_scope.base, init_result_loc, var_decl.ast.init_node);1205 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;
1211 if (init_scope.rvalue_rl_count == 1) {1207 if (init_scope.rvalue_rl_count == 1) {
1212 // Result location pointer not used. We don't need an alloc for this1208 // Result location pointer not used. We don't need an alloc for this
1213 // const local, and type inference becomes trivial.1209 // const local, and type inference becomes trivial.
...@@ -1231,7 +1227,7 @@ fn varDecl(...@@ -1231,7 +1227,7 @@ fn varDecl(
1231 const sub_scope = try block_arena.create(Scope.LocalVal);1227 const sub_scope = try block_arena.create(Scope.LocalVal);
1232 sub_scope.* = .{1228 sub_scope.* = .{
1233 .parent = scope,1229 .parent = scope,
1234 .gen_zir = scope.getGenZir(),1230 .gen_zir = gz,
1235 .name = ident_name,1231 .name = ident_name,
1236 .inst = casted_init,1232 .inst = casted_init,
1237 };1233 };
...@@ -1258,7 +1254,7 @@ fn varDecl(...@@ -1258,7 +1254,7 @@ fn varDecl(
1258 const sub_scope = try block_arena.create(Scope.LocalPtr);1254 const sub_scope = try block_arena.create(Scope.LocalPtr);
1259 sub_scope.* = .{1255 sub_scope.* = .{
1260 .parent = scope,1256 .parent = scope,
1261 .gen_zir = scope.getGenZir(),1257 .gen_zir = gz,
1262 .name = ident_name,1258 .name = ident_name,
1263 .ptr = init_scope.rl_ptr.?,1259 .ptr = init_scope.rl_ptr.?,
1264 };1260 };
...@@ -1285,9 +1281,10 @@ fn varDecl(...@@ -1285,9 +1281,10 @@ fn varDecl(
1285 const sub_scope = try block_arena.create(Scope.LocalPtr);1281 const sub_scope = try block_arena.create(Scope.LocalPtr);
1286 sub_scope.* = .{1282 sub_scope.* = .{
1287 .parent = scope,1283 .parent = scope,
1288 .gen_zir = scope.getGenZir(),1284 .gen_zir = gz,
1289 .name = ident_name,1285 .name = ident_name,
1290 .ptr = var_data.alloc,1286 .ptr = var_data.alloc,
1287 .src = gz.nodeSrcLoc(node),
1291 };1288 };
1292 return &sub_scope.base;1289 return &sub_scope.base;
1293 },1290 },
...@@ -2078,10 +2075,10 @@ fn copyBodyWithElidedStoreBlockPtr(body: *zir.Body, scope: Module.Scope.GenZir)...@@ -2078,10 +2075,10 @@ fn copyBodyWithElidedStoreBlockPtr(body: *zir.Body, scope: Module.Scope.GenZir)
2078 assert(dst_index == body.instructions.len);2075 assert(dst_index == body.instructions.len);
2079}2076}
20802077
2081fn copyBodyNoEliding(body: *zir.Body, scope: Module.Scope.GenZir) !void {2078fn copyBodyNoEliding(block_inst: zir.Inst.Index, gz: Module.Scope.GenZir) !void {
2082 body.* = .{2079 const zir_datas = gz.zir_code.instructions.items(.data);
2083 .instructions = try scope.arena.dupe(zir.Inst.Ref, scope.instructions.items),2080 zir_datas[block_inst].pl_node.payload_index = @intCast(u32, gz.zir_code.extra.items.len);
2084 };2081 try gz.zir_code.extra.appendSlice(gz.zir_code.gpa, gz.instructions.items);
2085}2082}
20862083
2087fn whileExpr(2084fn whileExpr(
...@@ -3515,7 +3512,7 @@ fn suspendExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!zir...@@ -3515,7 +3512,7 @@ fn suspendExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!zir
3515 return mod.failWithOwnedErrorMsg(scope, msg);3512 return mod.failWithOwnedErrorMsg(scope, msg);
3516 }3513 }
35173514
3518 var suspend_scope: Scope.GenZIR = .{3515 var suspend_scope: Scope.GenZir = .{
3519 .base = .{ .tag = .gen_suspend },3516 .base = .{ .tag = .gen_suspend },
3520 .parent = scope,3517 .parent = scope,
3521 .decl = scope.ownerDecl().?,3518 .decl = scope.ownerDecl().?,
...@@ -3864,7 +3861,10 @@ fn rvalue(...@@ -3864,7 +3861,10 @@ fn rvalue(
3864 const src_token = tree.firstToken(src_node);3861 const src_token = tree.firstToken(src_node);
3865 return gz.addUnTok(.ref, result, src_token);3862 return gz.addUnTok(.ref, result, src_token);
3866 },3863 },
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 }),
3868 .ptr => |ptr_inst| {3868 .ptr => |ptr_inst| {
3869 _ = try gz.addBin(.store, ptr_inst, result);3869 _ = try gz.addBin(.store, ptr_inst, result);
3870 return result;3870 return result;
...@@ -3953,17 +3953,17 @@ fn setBlockResultLoc(block_scope: *Scope.GenZir, parent_rl: ResultLoc) void {...@@ -3953,17 +3953,17 @@ fn setBlockResultLoc(block_scope: *Scope.GenZir, parent_rl: ResultLoc) void {
3953 },3953 },
39543954
3955 .inferred_ptr => |ptr| {3955 .inferred_ptr => |ptr| {
3956 block_scope.rl_ptr = &ptr.base;3956 block_scope.rl_ptr = ptr;
3957 block_scope.break_result_loc = .{ .block_ptr = block_scope };3957 block_scope.break_result_loc = .{ .block_ptr = block_scope };
3958 },3958 },
39593959
3960 .bitcasted_ptr => |ptr| {3960 .bitcasted_ptr => |ptr| {
3961 block_scope.rl_ptr = &ptr.base;3961 block_scope.rl_ptr = ptr;
3962 block_scope.break_result_loc = .{ .block_ptr = block_scope };3962 block_scope.break_result_loc = .{ .block_ptr = block_scope };
3963 },3963 },
39643964
3965 .block_ptr => |parent_block_scope| {3965 .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;
3967 block_scope.break_result_loc = .{ .block_ptr = block_scope };3967 block_scope.break_result_loc = .{ .block_ptr = block_scope };
3968 },3968 },
3969 }3969 }
src/zir.zig+36-4
...@@ -72,7 +72,7 @@ pub const Code = struct {...@@ -72,7 +72,7 @@ pub const Code = struct {
72 code: Code,72 code: Code,
73 gpa: *Allocator,73 gpa: *Allocator,
74 kind: []const u8,74 kind: []const u8,
75 decl_name: [*:0]const u8,75 scope: *Module.Scope,
76 param_count: usize,76 param_count: usize,
77 ) !void {77 ) !void {
78 var arena = std.heap.ArenaAllocator.init(gpa);78 var arena = std.heap.ArenaAllocator.init(gpa);
...@@ -81,11 +81,13 @@ pub const Code = struct {...@@ -81,11 +81,13 @@ pub const Code = struct {
81 var writer: Writer = .{81 var writer: Writer = .{
82 .gpa = gpa,82 .gpa = gpa,
83 .arena = &arena.allocator,83 .arena = &arena.allocator,
84 .scope = scope,
84 .code = code,85 .code = code,
85 .indent = 4,86 .indent = 4,
86 .param_count = param_count,87 .param_count = param_count,
87 };88 };
8889
90 const decl_name = scope.srcDecl().?.name;
89 const stderr = std.io.getStdErr().writer();91 const stderr = std.io.getStdErr().writer();
90 try stderr.print("ZIR {s} {s} {{\n", .{ kind, decl_name });92 try stderr.print("ZIR {s} {s} {{\n", .{ kind, decl_name });
9193
...@@ -416,9 +418,12 @@ pub const Inst = struct {...@@ -416,9 +418,12 @@ pub const Inst = struct {
416 /// error if the indexable object is not indexable.418 /// error if the indexable object is not indexable.
417 /// Uses the `un_node` field. The AST node is the for loop node.419 /// Uses the `un_node` field. The AST node is the for loop node.
418 indexable_ptr_len,420 indexable_ptr_len,
419 /// Type coercion.421 /// Type coercion. No source location attached.
420 /// Uses the `bin` field.422 /// Uses the `bin` field.
421 as,423 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,
422 /// Inline assembly. Non-volatile.427 /// Inline assembly. Non-volatile.
423 /// Uses the `pl_node` union field. Payload is `Asm`. AST node is the assembly node.428 /// Uses the `pl_node` union field. Payload is `Asm`. AST node is the assembly node.
424 @"asm",429 @"asm",
...@@ -464,12 +469,14 @@ pub const Inst = struct {...@@ -464,12 +469,14 @@ pub const Inst = struct {
464 /// Uses the `bin` field.469 /// Uses the `bin` field.
465 bool_or,470 bool_or,
466 /// Return a value from a block.471 /// 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.
468 /// Uses the source information from previous instruction.474 /// Uses the source information from previous instruction.
469 @"break",475 @"break",
470 /// Same as `break` but has source information in the form of a token, and476 /// Same as `break` but has source information in the form of a token, and
471 /// the operand is assumed to be the void value.477 /// the operand is assumed to be the void value.
472 /// Uses the `un_tok` union field.478 /// Uses the `un_tok` union field.
479 /// Note that the block operand is a `Index`, not `Ref`.
473 break_void_tok,480 break_void_tok,
474 /// Uses the `node` union field.481 /// Uses the `node` union field.
475 breakpoint,482 breakpoint,
...@@ -543,6 +550,9 @@ pub const Inst = struct {...@@ -543,6 +550,9 @@ pub const Inst = struct {
543 /// Same as `elem_val` except also stores a source location node.550 /// Same as `elem_val` except also stores a source location node.
544 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.551 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
545 elem_val_node,552 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,
546 /// Emits a compile error if the operand is not `void`.556 /// Emits a compile error if the operand is not `void`.
547 /// Uses the `un_node` field.557 /// Uses the `un_node` field.
548 ensure_result_used,558 ensure_result_used,
...@@ -671,6 +681,9 @@ pub const Inst = struct {...@@ -671,6 +681,9 @@ pub const Inst = struct {
671 /// Includes a token source location.681 /// Includes a token source location.
672 /// Uses the `un_tok` union field.682 /// Uses the `un_tok` union field.
673 ret_tok,683 ret_tok,
684 /// Same as `ret_tok` except the operand needs to get coerced to the function's
685 /// return type.
686 ret_coerce,
674 /// Changes the maximum number of backwards branches that compile-time687 /// Changes the maximum number of backwards branches that compile-time
675 /// code execution can use before giving up and making a compile error.688 /// code execution can use before giving up and making a compile error.
676 /// Uses the `un_node` union field.689 /// Uses the `un_node` union field.
...@@ -704,6 +717,7 @@ pub const Inst = struct {...@@ -704,6 +717,7 @@ pub const Inst = struct {
704 store,717 store,
705 /// Same as `store` but the type of the value being stored will be used to infer718 /// Same as `store` but the type of the value being stored will be used to infer
706 /// the block type. The LHS is the pointer to store to.719 /// the block type. The LHS is the pointer to store to.
720 /// Uses the `bin` union field.
707 store_to_block_ptr,721 store_to_block_ptr,
708 /// Same as `store` but the type of the value being stored will be used to infer722 /// Same as `store` but the type of the value being stored will be used to infer
709 /// the pointer type.723 /// the pointer type.
...@@ -854,6 +868,7 @@ pub const Inst = struct {...@@ -854,6 +868,7 @@ pub const Inst = struct {
854 .array_type_sentinel,868 .array_type_sentinel,
855 .indexable_ptr_len,869 .indexable_ptr_len,
856 .as,870 .as,
871 .as_node,
857 .@"asm",872 .@"asm",
858 .asm_volatile,873 .asm_volatile,
859 .bit_and,874 .bit_and,
...@@ -963,6 +978,7 @@ pub const Inst = struct {...@@ -963,6 +978,7 @@ pub const Inst = struct {
963 .@"resume",978 .@"resume",
964 .@"await",979 .@"await",
965 .nosuspend_await,980 .nosuspend_await,
981 .elided,
966 => false,982 => false,
967983
968 .@"break",984 .@"break",
...@@ -971,6 +987,7 @@ pub const Inst = struct {...@@ -971,6 +987,7 @@ pub const Inst = struct {
971 .compile_error,987 .compile_error,
972 .ret_node,988 .ret_node,
973 .ret_tok,989 .ret_tok,
990 .ret_coerce,
974 .unreachable_unsafe,991 .unreachable_unsafe,
975 .unreachable_safe,992 .unreachable_safe,
976 .loop,993 .loop,
...@@ -1242,11 +1259,17 @@ pub const Inst = struct {...@@ -1242,11 +1259,17 @@ pub const Inst = struct {
1242 lhs: Ref,1259 lhs: Ref,
1243 field_name: Ref,1260 field_name: Ref,
1244 };1261 };
1262
1263 pub const As = struct {
1264 dest_type: Ref,
1265 operand: Ref,
1266 };
1245};1267};
12461268
1247const Writer = struct {1269const Writer = struct {
1248 gpa: *Allocator,1270 gpa: *Allocator,
1249 arena: *Allocator,1271 arena: *Allocator,
1272 scope: *Module.Scope,
1250 code: Code,1273 code: Code,
1251 indent: usize,1274 indent: usize,
1252 param_count: usize,1275 param_count: usize,
...@@ -1325,6 +1348,7 @@ const Writer = struct {...@@ -1325,6 +1348,7 @@ const Writer = struct {
1325 .is_err_ptr,1348 .is_err_ptr,
1326 .ref,1349 .ref,
1327 .ret_tok,1350 .ret_tok,
1351 .ret_coerce,
1328 .typeof,1352 .typeof,
1329 .optional_type,1353 .optional_type,
1330 .optional_type_from_ptr_elem,1354 .optional_type_from_ptr_elem,
...@@ -1348,6 +1372,7 @@ const Writer = struct {...@@ -1348,6 +1372,7 @@ const Writer = struct {
1348 .ptr_type => try self.writePtrType(stream, inst),1372 .ptr_type => try self.writePtrType(stream, inst),
1349 .int => try self.writeInt(stream, inst),1373 .int => try self.writeInt(stream, inst),
1350 .str => try self.writeStr(stream, inst),1374 .str => try self.writeStr(stream, inst),
1375 .elided => try stream.writeAll(")"),
13511376
1352 .@"asm",1377 .@"asm",
1353 .asm_volatile,1378 .asm_volatile,
...@@ -1374,6 +1399,7 @@ const Writer = struct {...@@ -1374,6 +1399,7 @@ const Writer = struct {
1374 .slice_sentinel,1399 .slice_sentinel,
1375 .typeof_peer,1400 .typeof_peer,
1376 .suspend_block,1401 .suspend_block,
1402 .as_node,
1377 => try self.writePlNode(stream, inst),1403 => try self.writePlNode(stream, inst),
13781404
1379 .breakpoint,1405 .breakpoint,
...@@ -1641,6 +1667,12 @@ const Writer = struct {...@@ -1641,6 +1667,12 @@ const Writer = struct {
1641 }1667 }
16421668
1643 fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void {1669 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 });
1645 }1677 }
1646};1678};