authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-08-19 08:45:30+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-08-21 01:30:46+01:00
log43fdd061f7430794c142283101f9c97a0829d446
tree9d37f8b99735e51b290472d45f5e9b2b61aa7b3e
parent95fbfde9daa165ca74a4d7267720fd32b42af45e
signaturelock-open Commit is signed but in an unrecognized format.

AstGen: incorporate extra information into source hashes

* Indices of referenced captures * Line and column of `@src()` The second point aligns with a reversal of the "incremental compilation" section of https://github.com/ziglang/zig/issues/2029#issuecomment-645793168. This reversal was already done as #17688 (46a6d50), with the idea to push incremental compilation down the line. My proposal is to keep it as comptime-known, and simply re-analyze uses of `@src()` whenever their line/column change. I think this decision is reasonable for a few reasons: * The Zig compiler is quite fast. Occasionally re-analyzing a few functions containing `@src()` calls is perfectly acceptable and won't noticably impact update times. * The system described by Andrew in #2029 is currently vaporware. * The system described by Andrew in #2029 is non-trivial to implement. In particular, it requires some way to have backends update a single global in certain cases, without re-doing semantic analysis. There is no other part of incremental compilation which requires this. * Having `@src().line` be comptime-known is useful. For instance, #17688 was justified by broken Tracy integration because the source line couldn't be comptime-known.

1 files changed, 107 insertions(+), 30 deletions(-)

lib/std/zig/AstGen.zig+107-30
...@@ -66,6 +66,10 @@ scratch: std.ArrayListUnmanaged(u32) = .{},...@@ -66,6 +66,10 @@ scratch: std.ArrayListUnmanaged(u32) = .{},
66/// of ZIR.66/// of ZIR.
67/// The key is the ref operand; the value is the ref instruction.67/// The key is the ref operand; the value is the ref instruction.
68ref_table: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{},68ref_table: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{},
69/// Any information which should trigger invalidation of incremental compilation
70/// data should be used to update this hasher. The result is the final source
71/// hash of the enclosing declaration/etc.
72src_hasher: std.zig.SrcHasher,
6973
70const InnerError = error{ OutOfMemory, AnalysisFail };74const InnerError = error{ OutOfMemory, AnalysisFail };
7175
...@@ -137,6 +141,7 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {...@@ -137,6 +141,7 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
137 .arena = arena.allocator(),141 .arena = arena.allocator(),
138 .tree = &tree,142 .tree = &tree,
139 .nodes_need_rl = &nodes_need_rl,143 .nodes_need_rl = &nodes_need_rl,
144 .src_hasher = undefined, // `structDeclInner` for the root struct will set this
140 };145 };
141 defer astgen.deinit(gpa);146 defer astgen.deinit(gpa);
142147
...@@ -1422,6 +1427,8 @@ fn fnProtoExpr(...@@ -1422,6 +1427,8 @@ fn fnProtoExpr(
1422 .is_extern = false,1427 .is_extern = false,
1423 .is_noinline = false,1428 .is_noinline = false,
1424 .noalias_bits = noalias_bits,1429 .noalias_bits = noalias_bits,
1430
1431 .proto_hash = undefined, // ignored for `body_gz == null`
1425 });1432 });
14261433
1427 _ = try block_scope.addBreak(.break_inline, block_inst, result);1434 _ = try block_scope.addBreak(.break_inline, block_inst, result);
...@@ -4007,6 +4014,13 @@ fn fnDecl(...@@ -4007,6 +4014,13 @@ fn fnDecl(
4007 const tree = astgen.tree;4014 const tree = astgen.tree;
4008 const token_tags = tree.tokens.items(.tag);4015 const token_tags = tree.tokens.items(.tag);
40094016
4017 const old_hasher = astgen.src_hasher;
4018 defer astgen.src_hasher = old_hasher;
4019 astgen.src_hasher = std.zig.SrcHasher.init(.{});
4020 // We don't add the full source yet, because we also need the prototype hash!
4021 // The source slice is added towards the *end* of this function.
4022 astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
4023
4010 // missing function name already happened in scanDecls()4024 // missing function name already happened in scanDecls()
4011 const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail;4025 const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail;
40124026
...@@ -4300,11 +4314,21 @@ fn fnDecl(...@@ -4300,11 +4314,21 @@ fn fnDecl(
4300 .is_extern = true,4314 .is_extern = true,
4301 .is_noinline = is_noinline,4315 .is_noinline = is_noinline,
4302 .noalias_bits = noalias_bits,4316 .noalias_bits = noalias_bits,
4317 .proto_hash = undefined, // ignored for `body_gz == null`
4303 });4318 });
4304 } else func: {4319 } else func: {
4305 // as a scope, fn_gz encloses ret_gz, but for instruction list, fn_gz stacks on ret_gz4320 // as a scope, fn_gz encloses ret_gz, but for instruction list, fn_gz stacks on ret_gz
4306 fn_gz.instructions_top = ret_gz.instructions.items.len;4321 fn_gz.instructions_top = ret_gz.instructions.items.len;
43074322
4323 // Construct the prototype hash.
4324 // Leave `astgen.src_hasher` unmodified; this will be used for hashing
4325 // the *whole* function declaration, including its body.
4326 var proto_hasher = astgen.src_hasher;
4327 const proto_node = tree.nodes.items(.data)[decl_node].lhs;
4328 proto_hasher.update(tree.getNodeSource(proto_node));
4329 var proto_hash: std.zig.SrcHash = undefined;
4330 proto_hasher.final(&proto_hash);
4331
4308 const prev_fn_block = astgen.fn_block;4332 const prev_fn_block = astgen.fn_block;
4309 const prev_fn_ret_ty = astgen.fn_ret_ty;4333 const prev_fn_ret_ty = astgen.fn_ret_ty;
4310 defer {4334 defer {
...@@ -4362,16 +4386,22 @@ fn fnDecl(...@@ -4362,16 +4386,22 @@ fn fnDecl(
4362 .is_extern = false,4386 .is_extern = false,
4363 .is_noinline = is_noinline,4387 .is_noinline = is_noinline,
4364 .noalias_bits = noalias_bits,4388 .noalias_bits = noalias_bits,
4389 .proto_hash = proto_hash,
4365 });4390 });
4366 };4391 };
43674392
4393 // *Now* we can incorporate the full source code into the hasher.
4394 astgen.src_hasher.update(tree.getNodeSource(decl_node));
4395
4368 // We add this at the end so that its instruction index marks the end range4396 // We add this at the end so that its instruction index marks the end range
4369 // of the top level declaration. addFunc already unstacked fn_gz and ret_gz.4397 // of the top level declaration. addFunc already unstacked fn_gz and ret_gz.
4370 _ = try decl_gz.addBreak(.break_inline, decl_inst, func_inst);4398 _ = try decl_gz.addBreak(.break_inline, decl_inst, func_inst);
43714399
4400 var hash: std.zig.SrcHash = undefined;
4401 astgen.src_hasher.final(&hash);
4372 try setDeclaration(4402 try setDeclaration(
4373 decl_inst,4403 decl_inst,
4374 std.zig.hashSrc(tree.getNodeSource(decl_node)),4404 hash,
4375 .{ .named = fn_name_token },4405 .{ .named = fn_name_token },
4376 decl_gz.decl_line,4406 decl_gz.decl_line,
4377 is_pub,4407 is_pub,
...@@ -4395,6 +4425,12 @@ fn globalVarDecl(...@@ -4395,6 +4425,12 @@ fn globalVarDecl(
4395 const tree = astgen.tree;4425 const tree = astgen.tree;
4396 const token_tags = tree.tokens.items(.tag);4426 const token_tags = tree.tokens.items(.tag);
43974427
4428 const old_hasher = astgen.src_hasher;
4429 defer astgen.src_hasher = old_hasher;
4430 astgen.src_hasher = std.zig.SrcHasher.init(.{});
4431 astgen.src_hasher.update(tree.getNodeSource(node));
4432 astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
4433
4398 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;4434 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
4399 // We do this at the beginning so that the instruction index marks the range start4435 // We do this at the beginning so that the instruction index marks the range start
4400 // of the top level declaration.4436 // of the top level declaration.
...@@ -4534,9 +4570,11 @@ fn globalVarDecl(...@@ -4534,9 +4570,11 @@ fn globalVarDecl(
4534 _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node);4570 _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node);
4535 }4571 }
45364572
4573 var hash: std.zig.SrcHash = undefined;
4574 astgen.src_hasher.final(&hash);
4537 try setDeclaration(4575 try setDeclaration(
4538 decl_inst,4576 decl_inst,
4539 std.zig.hashSrc(tree.getNodeSource(node)),4577 hash,
4540 .{ .named = name_token },4578 .{ .named = name_token },
4541 block_scope.decl_line,4579 block_scope.decl_line,
4542 is_pub,4580 is_pub,
...@@ -4562,6 +4600,12 @@ fn comptimeDecl(...@@ -4562,6 +4600,12 @@ fn comptimeDecl(
4562 const node_datas = tree.nodes.items(.data);4600 const node_datas = tree.nodes.items(.data);
4563 const body_node = node_datas[node].lhs;4601 const body_node = node_datas[node].lhs;
45644602
4603 const old_hasher = astgen.src_hasher;
4604 defer astgen.src_hasher = old_hasher;
4605 astgen.src_hasher = std.zig.SrcHasher.init(.{});
4606 astgen.src_hasher.update(tree.getNodeSource(node));
4607 astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
4608
4565 // Up top so the ZIR instruction index marks the start range of this4609 // Up top so the ZIR instruction index marks the start range of this
4566 // top-level declaration.4610 // top-level declaration.
4567 const decl_inst = try gz.makeDeclaration(node);4611 const decl_inst = try gz.makeDeclaration(node);
...@@ -4584,9 +4628,11 @@ fn comptimeDecl(...@@ -4584,9 +4628,11 @@ fn comptimeDecl(
4584 _ = try decl_block.addBreak(.break_inline, decl_inst, .void_value);4628 _ = try decl_block.addBreak(.break_inline, decl_inst, .void_value);
4585 }4629 }
45864630
4631 var hash: std.zig.SrcHash = undefined;
4632 astgen.src_hasher.final(&hash);
4587 try setDeclaration(4633 try setDeclaration(
4588 decl_inst,4634 decl_inst,
4589 std.zig.hashSrc(tree.getNodeSource(node)),4635 hash,
4590 .@"comptime",4636 .@"comptime",
4591 decl_block.decl_line,4637 decl_block.decl_line,
4592 false,4638 false,
...@@ -4607,6 +4653,12 @@ fn usingnamespaceDecl(...@@ -4607,6 +4653,12 @@ fn usingnamespaceDecl(
4607 const tree = astgen.tree;4653 const tree = astgen.tree;
4608 const node_datas = tree.nodes.items(.data);4654 const node_datas = tree.nodes.items(.data);
46094655
4656 const old_hasher = astgen.src_hasher;
4657 defer astgen.src_hasher = old_hasher;
4658 astgen.src_hasher = std.zig.SrcHasher.init(.{});
4659 astgen.src_hasher.update(tree.getNodeSource(node));
4660 astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
4661
4610 const type_expr = node_datas[node].lhs;4662 const type_expr = node_datas[node].lhs;
4611 const is_pub = blk: {4663 const is_pub = blk: {
4612 const main_tokens = tree.nodes.items(.main_token);4664 const main_tokens = tree.nodes.items(.main_token);
...@@ -4634,9 +4686,11 @@ fn usingnamespaceDecl(...@@ -4634,9 +4686,11 @@ fn usingnamespaceDecl(
4634 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);4686 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);
4635 _ = try decl_block.addBreak(.break_inline, decl_inst, namespace_inst);4687 _ = try decl_block.addBreak(.break_inline, decl_inst, namespace_inst);
46364688
4689 var hash: std.zig.SrcHash = undefined;
4690 astgen.src_hasher.final(&hash);
4637 try setDeclaration(4691 try setDeclaration(
4638 decl_inst,4692 decl_inst,
4639 std.zig.hashSrc(tree.getNodeSource(node)),4693 hash,
4640 .@"usingnamespace",4694 .@"usingnamespace",
4641 decl_block.decl_line,4695 decl_block.decl_line,
4642 is_pub,4696 is_pub,
...@@ -4658,6 +4712,12 @@ fn testDecl(...@@ -4658,6 +4712,12 @@ fn testDecl(
4658 const node_datas = tree.nodes.items(.data);4712 const node_datas = tree.nodes.items(.data);
4659 const body_node = node_datas[node].rhs;4713 const body_node = node_datas[node].rhs;
46604714
4715 const old_hasher = astgen.src_hasher;
4716 defer astgen.src_hasher = old_hasher;
4717 astgen.src_hasher = std.zig.SrcHasher.init(.{});
4718 astgen.src_hasher.update(tree.getNodeSource(node));
4719 astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
4720
4661 // Up top so the ZIR instruction index marks the start range of this4721 // Up top so the ZIR instruction index marks the start range of this
4662 // top-level declaration.4722 // top-level declaration.
4663 const decl_inst = try gz.makeDeclaration(node);4723 const decl_inst = try gz.makeDeclaration(node);
...@@ -4819,13 +4879,18 @@ fn testDecl(...@@ -4819,13 +4879,18 @@ fn testDecl(
4819 .is_extern = false,4879 .is_extern = false,
4820 .is_noinline = false,4880 .is_noinline = false,
4821 .noalias_bits = 0,4881 .noalias_bits = 0,
4882
4883 // Tests don't have a prototype that needs hashing
4884 .proto_hash = .{0} ** 16,
4822 });4885 });
48234886
4824 _ = try decl_block.addBreak(.break_inline, decl_inst, func_inst);4887 _ = try decl_block.addBreak(.break_inline, decl_inst, func_inst);
48254888
4889 var hash: std.zig.SrcHash = undefined;
4890 astgen.src_hasher.final(&hash);
4826 try setDeclaration(4891 try setDeclaration(
4827 decl_inst,4892 decl_inst,
4828 std.zig.hashSrc(tree.getNodeSource(node)),4893 hash,
4829 test_name,4894 test_name,
4830 decl_block.decl_line,4895 decl_block.decl_line,
4831 false,4896 false,
...@@ -4983,10 +5048,12 @@ fn structDeclInner(...@@ -4983,10 +5048,12 @@ fn structDeclInner(
4983 }5048 }
4984 };5049 };
49855050
4986 var fields_hasher = std.zig.SrcHasher.init(.{});5051 const old_hasher = astgen.src_hasher;
4987 fields_hasher.update(@tagName(layout));5052 defer astgen.src_hasher = old_hasher;
5053 astgen.src_hasher = std.zig.SrcHasher.init(.{});
5054 astgen.src_hasher.update(@tagName(layout));
4988 if (backing_int_node != 0) {5055 if (backing_int_node != 0) {
4989 fields_hasher.update(tree.getNodeSource(backing_int_node));5056 astgen.src_hasher.update(tree.getNodeSource(backing_int_node));
4990 }5057 }
49915058
4992 var sfba = std.heap.stackFallback(256, astgen.arena);5059 var sfba = std.heap.stackFallback(256, astgen.arena);
...@@ -5009,7 +5076,7 @@ fn structDeclInner(...@@ -5009,7 +5076,7 @@ fn structDeclInner(
5009 .field => |field| field,5076 .field => |field| field,
5010 };5077 };
50115078
5012 fields_hasher.update(tree.getNodeSource(member_node));5079 astgen.src_hasher.update(tree.getNodeSource(member_node));
50135080
5014 if (!is_tuple) {5081 if (!is_tuple) {
5015 const field_name = try astgen.identAsString(member.ast.main_token);5082 const field_name = try astgen.identAsString(member.ast.main_token);
...@@ -5139,7 +5206,7 @@ fn structDeclInner(...@@ -5139,7 +5206,7 @@ fn structDeclInner(
5139 }5206 }
51405207
5141 var fields_hash: std.zig.SrcHash = undefined;5208 var fields_hash: std.zig.SrcHash = undefined;
5142 fields_hasher.final(&fields_hash);5209 astgen.src_hasher.final(&fields_hash);
51435210
5144 try gz.setStruct(decl_inst, .{5211 try gz.setStruct(decl_inst, .{
5145 .src_node = node,5212 .src_node = node,
...@@ -5240,11 +5307,13 @@ fn unionDeclInner(...@@ -5240,11 +5307,13 @@ fn unionDeclInner(
5240 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);5307 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);
5241 defer wip_members.deinit();5308 defer wip_members.deinit();
52425309
5243 var fields_hasher = std.zig.SrcHasher.init(.{});5310 const old_hasher = astgen.src_hasher;
5244 fields_hasher.update(@tagName(layout));5311 defer astgen.src_hasher = old_hasher;
5245 fields_hasher.update(&.{@intFromBool(auto_enum_tok != null)});5312 astgen.src_hasher = std.zig.SrcHasher.init(.{});
5313 astgen.src_hasher.update(@tagName(layout));
5314 astgen.src_hasher.update(&.{@intFromBool(auto_enum_tok != null)});
5246 if (arg_node != 0) {5315 if (arg_node != 0) {
5247 fields_hasher.update(astgen.tree.getNodeSource(arg_node));5316 astgen.src_hasher.update(astgen.tree.getNodeSource(arg_node));
5248 }5317 }
52495318
5250 var sfba = std.heap.stackFallback(256, astgen.arena);5319 var sfba = std.heap.stackFallback(256, astgen.arena);
...@@ -5261,7 +5330,7 @@ fn unionDeclInner(...@@ -5261,7 +5330,7 @@ fn unionDeclInner(
5261 .decl => continue,5330 .decl => continue,
5262 .field => |field| field,5331 .field => |field| field,
5263 };5332 };
5264 fields_hasher.update(astgen.tree.getNodeSource(member_node));5333 astgen.src_hasher.update(astgen.tree.getNodeSource(member_node));
5265 member.convertToNonTupleLike(astgen.tree.nodes);5334 member.convertToNonTupleLike(astgen.tree.nodes);
5266 if (member.ast.tuple_like) {5335 if (member.ast.tuple_like) {
5267 return astgen.failTok(member.ast.main_token, "union field missing name", .{});5336 return astgen.failTok(member.ast.main_token, "union field missing name", .{});
...@@ -5364,7 +5433,7 @@ fn unionDeclInner(...@@ -5364,7 +5433,7 @@ fn unionDeclInner(
5364 }5433 }
53655434
5366 var fields_hash: std.zig.SrcHash = undefined;5435 var fields_hash: std.zig.SrcHash = undefined;
5367 fields_hasher.final(&fields_hash);5436 astgen.src_hasher.final(&fields_hash);
53685437
5369 if (!block_scope.isEmpty()) {5438 if (!block_scope.isEmpty()) {
5370 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);5439 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
...@@ -5578,11 +5647,13 @@ fn containerDecl(...@@ -5578,11 +5647,13 @@ fn containerDecl(
5578 var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(counts.decls), @intCast(counts.total_fields), bits_per_field, max_field_size);5647 var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(counts.decls), @intCast(counts.total_fields), bits_per_field, max_field_size);
5579 defer wip_members.deinit();5648 defer wip_members.deinit();
55805649
5581 var fields_hasher = std.zig.SrcHasher.init(.{});5650 const old_hasher = astgen.src_hasher;
5651 defer astgen.src_hasher = old_hasher;
5652 astgen.src_hasher = std.zig.SrcHasher.init(.{});
5582 if (container_decl.ast.arg != 0) {5653 if (container_decl.ast.arg != 0) {
5583 fields_hasher.update(tree.getNodeSource(container_decl.ast.arg));5654 astgen.src_hasher.update(tree.getNodeSource(container_decl.ast.arg));
5584 }5655 }
5585 fields_hasher.update(&.{@intFromBool(nonexhaustive)});5656 astgen.src_hasher.update(&.{@intFromBool(nonexhaustive)});
55865657
5587 var sfba = std.heap.stackFallback(256, astgen.arena);5658 var sfba = std.heap.stackFallback(256, astgen.arena);
5588 const sfba_allocator = sfba.get();5659 const sfba_allocator = sfba.get();
...@@ -5596,7 +5667,7 @@ fn containerDecl(...@@ -5596,7 +5667,7 @@ fn containerDecl(
5596 for (container_decl.ast.members) |member_node| {5667 for (container_decl.ast.members) |member_node| {
5597 if (member_node == counts.nonexhaustive_node)5668 if (member_node == counts.nonexhaustive_node)
5598 continue;5669 continue;
5599 fields_hasher.update(tree.getNodeSource(member_node));5670 astgen.src_hasher.update(tree.getNodeSource(member_node));
5600 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {5671 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
5601 .decl => continue,5672 .decl => continue,
5602 .field => |field| field,5673 .field => |field| field,
...@@ -5676,7 +5747,7 @@ fn containerDecl(...@@ -5676,7 +5747,7 @@ fn containerDecl(
5676 }5747 }
56775748
5678 var fields_hash: std.zig.SrcHash = undefined;5749 var fields_hash: std.zig.SrcHash = undefined;
5679 fields_hasher.final(&fields_hash);5750 astgen.src_hasher.final(&fields_hash);
56805751
5681 const body = block_scope.instructionsSlice();5752 const body = block_scope.instructionsSlice();
5682 const body_len = astgen.countBodyLenAfterFixups(body);5753 const body_len = astgen.countBodyLenAfterFixups(body);
...@@ -8478,6 +8549,10 @@ fn tunnelThroughClosure(...@@ -8478,6 +8549,10 @@ fn tunnelThroughClosure(
8478 });8549 });
8479 }8550 }
84808551
8552 // Incorporate the capture index into the source hash, so that changes in
8553 // the order of captures cause suitable re-analysis.
8554 astgen.src_hasher.update(std.mem.asBytes(&cur_capture_index));
8555
8481 // Add an instruction to get the value from the closure.8556 // Add an instruction to get the value from the closure.
8482 return gz.addExtendedNodeSmall(.closure_get, inner_ref_node, cur_capture_index);8557 return gz.addExtendedNodeSmall(.closure_get, inner_ref_node, cur_capture_index);
8483}8558}
...@@ -9306,6 +9381,13 @@ fn builtinCall(...@@ -9306,6 +9381,13 @@ fn builtinCall(
9306 },9381 },
93079382
9308 .src => {9383 .src => {
9384 // Incorporate the source location into the source hash, so that
9385 // changes in the source location of `@src()` result in re-analysis.
9386 astgen.src_hasher.update(
9387 std.mem.asBytes(&astgen.source_line) ++
9388 std.mem.asBytes(&astgen.source_column),
9389 );
9390
9309 const token_starts = tree.tokens.items(.start);9391 const token_starts = tree.tokens.items(.start);
9310 const node_start = token_starts[tree.firstToken(node)];9392 const node_start = token_starts[tree.firstToken(node)];
9311 astgen.advanceSourceCursor(node_start);9393 astgen.advanceSourceCursor(node_start);
...@@ -12122,6 +12204,9 @@ const GenZir = struct {...@@ -12122,6 +12204,9 @@ const GenZir = struct {
12122 is_test: bool,12204 is_test: bool,
12123 is_extern: bool,12205 is_extern: bool,
12124 is_noinline: bool,12206 is_noinline: bool,
12207
12208 /// Ignored if `body_gz == null`.
12209 proto_hash: std.zig.SrcHash,
12125 }) !Zir.Inst.Ref {12210 }) !Zir.Inst.Ref {
12126 assert(args.src_node != 0);12211 assert(args.src_node != 0);
12127 const astgen = gz.astgen;12212 const astgen = gz.astgen;
...@@ -12150,15 +12235,7 @@ const GenZir = struct {...@@ -12150,15 +12235,7 @@ const GenZir = struct {
1215012235
12151 const columns = args.lbrace_column | (rbrace_column << 16);12236 const columns = args.lbrace_column | (rbrace_column << 16);
1215212237
12153 const proto_hash: std.zig.SrcHash = switch (node_tags[fn_decl]) {12238 const proto_hash_arr: [4]u32 = @bitCast(args.proto_hash);
12154 .fn_decl => sig_hash: {
12155 const proto_node = node_datas[fn_decl].lhs;
12156 break :sig_hash std.zig.hashSrc(tree.getNodeSource(proto_node));
12157 },
12158 .test_decl => std.zig.hashSrc(""), // tests don't have a prototype
12159 else => unreachable,
12160 };
12161 const proto_hash_arr: [4]u32 = @bitCast(proto_hash);
1216212239
12163 src_locs_and_hash_buffer = .{12240 src_locs_and_hash_buffer = .{
12164 args.lbrace_line,12241 args.lbrace_line,