@@ -66,6 +66,10 @@ scratch: std.ArrayListUnmanaged(u32) = .{},
66
66
/// of ZIR.
67
67
/// The key is the ref operand; the value is the ref instruction.
68
68
ref_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.
72
+ src_hasher: std.zig.SrcHasher,
69
73
70
74
const InnerError = error{ OutOfMemory, AnalysisFail };
71
75
@@ -137,6 +141,7 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
137
141
.arena = arena.allocator(),
138
142
.tree = &tree,
139
143
.nodes_need_rl = &nodes_need_rl,
144
+ .src_hasher = undefined, // `structDeclInner` for the root struct will set this
140
145
};
141
146
defer astgen.deinit(gpa);
142
147
@@ -1422,6 +1427,8 @@ fn fnProtoExpr(
1422
1427
.is_extern = false,
1423
1428
.is_noinline = false,
1424
1429
.noalias_bits = noalias_bits,
1430
+
1431
+ .proto_hash = undefined, // ignored for `body_gz == null`
1425
1432
});
1426
1433
1427
1434
_ = try block_scope.addBreak(.break_inline, block_inst, result);
@@ -4007,6 +4014,13 @@ fn fnDecl(
4007
4014
const tree = astgen.tree;
4008
4015
const token_tags = tree.tokens.items(.tag);
4009
4016
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
4024
// missing function name already happened in scanDecls()
4011
4025
const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail;
4012
4026
@@ -4300,11 +4314,21 @@ fn fnDecl(
4300
4314
.is_extern = true,
4301
4315
.is_noinline = is_noinline,
4302
4316
.noalias_bits = noalias_bits,
4317
+ .proto_hash = undefined, // ignored for `body_gz == null`
4303
4318
});
4304
4319
} else func: {
4305
4320
// as a scope, fn_gz encloses ret_gz, but for instruction list, fn_gz stacks on ret_gz
4306
4321
fn_gz.instructions_top = ret_gz.instructions.items.len;
4307
4322
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
4332
const prev_fn_block = astgen.fn_block;
4309
4333
const prev_fn_ret_ty = astgen.fn_ret_ty;
4310
4334
defer {
@@ -4362,16 +4386,22 @@ fn fnDecl(
4362
4386
.is_extern = false,
4363
4387
.is_noinline = is_noinline,
4364
4388
.noalias_bits = noalias_bits,
4389
+ .proto_hash = proto_hash,
4365
4390
});
4366
4391
};
4367
4392
4393
+ // *Now* we can incorporate the full source code into the hasher.
4394
+ astgen.src_hasher.update(tree.getNodeSource(decl_node));
4395
+
4368
4396
// We add this at the end so that its instruction index marks the end range
4369
4397
// of the top level declaration. addFunc already unstacked fn_gz and ret_gz.
4370
4398
_ = try decl_gz.addBreak(.break_inline, decl_inst, func_inst);
4371
4399
4400
+ var hash: std.zig.SrcHash = undefined;
4401
+ astgen.src_hasher.final(&hash);
4372
4402
try setDeclaration(
4373
4403
decl_inst,
4374
- std.zig.hashSrc(tree.getNodeSource(decl_node)) ,
4404
+ hash ,
4375
4405
.{ .named = fn_name_token },
4376
4406
decl_gz.decl_line,
4377
4407
is_pub,
@@ -4395,6 +4425,12 @@ fn globalVarDecl(
4395
4425
const tree = astgen.tree;
4396
4426
const token_tags = tree.tokens.items(.tag);
4397
4427
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
4434
const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
4399
4435
// We do this at the beginning so that the instruction index marks the range start
4400
4436
// of the top level declaration.
@@ -4534,9 +4570,11 @@ fn globalVarDecl(
4534
4570
_ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node);
4535
4571
}
4536
4572
4573
+ var hash: std.zig.SrcHash = undefined;
4574
+ astgen.src_hasher.final(&hash);
4537
4575
try setDeclaration(
4538
4576
decl_inst,
4539
- std.zig.hashSrc(tree.getNodeSource(node)) ,
4577
+ hash ,
4540
4578
.{ .named = name_token },
4541
4579
block_scope.decl_line,
4542
4580
is_pub,
@@ -4562,6 +4600,12 @@ fn comptimeDecl(
4562
4600
const node_datas = tree.nodes.items(.data);
4563
4601
const body_node = node_datas[node].lhs;
4564
4602
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
4609
// Up top so the ZIR instruction index marks the start range of this
4566
4610
// top-level declaration.
4567
4611
const decl_inst = try gz.makeDeclaration(node);
@@ -4584,9 +4628,11 @@ fn comptimeDecl(
4584
4628
_ = try decl_block.addBreak(.break_inline, decl_inst, .void_value);
4585
4629
}
4586
4630
4631
+ var hash: std.zig.SrcHash = undefined;
4632
+ astgen.src_hasher.final(&hash);
4587
4633
try setDeclaration(
4588
4634
decl_inst,
4589
- std.zig.hashSrc(tree.getNodeSource(node)) ,
4635
+ hash ,
4590
4636
.@"comptime",
4591
4637
decl_block.decl_line,
4592
4638
false,
@@ -4607,6 +4653,12 @@ fn usingnamespaceDecl(
4607
4653
const tree = astgen.tree;
4608
4654
const node_datas = tree.nodes.items(.data);
4609
4655
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
4662
const type_expr = node_datas[node].lhs;
4611
4663
const is_pub = blk: {
4612
4664
const main_tokens = tree.nodes.items(.main_token);
@@ -4634,9 +4686,11 @@ fn usingnamespaceDecl(
4634
4686
const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);
4635
4687
_ = try decl_block.addBreak(.break_inline, decl_inst, namespace_inst);
4636
4688
4689
+ var hash: std.zig.SrcHash = undefined;
4690
+ astgen.src_hasher.final(&hash);
4637
4691
try setDeclaration(
4638
4692
decl_inst,
4639
- std.zig.hashSrc(tree.getNodeSource(node)) ,
4693
+ hash ,
4640
4694
.@"usingnamespace",
4641
4695
decl_block.decl_line,
4642
4696
is_pub,
@@ -4658,6 +4712,12 @@ fn testDecl(
4658
4712
const node_datas = tree.nodes.items(.data);
4659
4713
const body_node = node_datas[node].rhs;
4660
4714
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
4721
// Up top so the ZIR instruction index marks the start range of this
4662
4722
// top-level declaration.
4663
4723
const decl_inst = try gz.makeDeclaration(node);
@@ -4819,13 +4879,18 @@ fn testDecl(
4819
4879
.is_extern = false,
4820
4880
.is_noinline = false,
4821
4881
.noalias_bits = 0,
4882
+
4883
+ // Tests don't have a prototype that needs hashing
4884
+ .proto_hash = .{0} ** 16,
4822
4885
});
4823
4886
4824
4887
_ = try decl_block.addBreak(.break_inline, decl_inst, func_inst);
4825
4888
4889
+ var hash: std.zig.SrcHash = undefined;
4890
+ astgen.src_hasher.final(&hash);
4826
4891
try setDeclaration(
4827
4892
decl_inst,
4828
- std.zig.hashSrc(tree.getNodeSource(node)) ,
4893
+ hash ,
4829
4894
test_name,
4830
4895
decl_block.decl_line,
4831
4896
false,
@@ -4983,10 +5048,12 @@ fn structDeclInner(
4983
5048
}
4984
5049
};
4985
5050
4986
- var fields_hasher = std.zig.SrcHasher.init(.{});
4987
- fields_hasher.update(@tagName(layout));
5051
+ const old_hasher = astgen.src_hasher;
5052
+ defer astgen.src_hasher = old_hasher;
5053
+ astgen.src_hasher = std.zig.SrcHasher.init(.{});
5054
+ astgen.src_hasher.update(@tagName(layout));
4988
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
}
4991
5058
4992
5059
var sfba = std.heap.stackFallback(256, astgen.arena);
@@ -5009,7 +5076,7 @@ fn structDeclInner(
5009
5076
.field => |field| field,
5010
5077
};
5011
5078
5012
- fields_hasher .update(tree.getNodeSource(member_node));
5079
+ astgen.src_hasher .update(tree.getNodeSource(member_node));
5013
5080
5014
5081
if (!is_tuple) {
5015
5082
const field_name = try astgen.identAsString(member.ast.main_token);
@@ -5139,7 +5206,7 @@ fn structDeclInner(
5139
5206
}
5140
5207
5141
5208
var fields_hash: std.zig.SrcHash = undefined;
5142
- fields_hasher .final(&fields_hash);
5209
+ astgen.src_hasher .final(&fields_hash);
5143
5210
5144
5211
try gz.setStruct(decl_inst, .{
5145
5212
.src_node = node,
@@ -5240,11 +5307,13 @@ fn unionDeclInner(
5240
5307
var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);
5241
5308
defer wip_members.deinit();
5242
5309
5243
- var fields_hasher = std.zig.SrcHasher.init(.{});
5244
- fields_hasher.update(@tagName(layout));
5245
- fields_hasher.update(&.{@intFromBool(auto_enum_tok != null)});
5310
+ const old_hasher = astgen.src_hasher;
5311
+ defer astgen.src_hasher = old_hasher;
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
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
}
5249
5318
5250
5319
var sfba = std.heap.stackFallback(256, astgen.arena);
@@ -5261,7 +5330,7 @@ fn unionDeclInner(
5261
5330
.decl => continue,
5262
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
5334
member.convertToNonTupleLike(astgen.tree.nodes);
5266
5335
if (member.ast.tuple_like) {
5267
5336
return astgen.failTok(member.ast.main_token, "union field missing name", .{});
@@ -5364,7 +5433,7 @@ fn unionDeclInner(
5364
5433
}
5365
5434
5366
5435
var fields_hash: std.zig.SrcHash = undefined;
5367
- fields_hasher .final(&fields_hash);
5436
+ astgen.src_hasher .final(&fields_hash);
5368
5437
5369
5438
if (!block_scope.isEmpty()) {
5370
5439
_ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
@@ -5578,11 +5647,13 @@ fn containerDecl(
5578
5647
var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(counts.decls), @intCast(counts.total_fields), bits_per_field, max_field_size);
5579
5648
defer wip_members.deinit();
5580
5649
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
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)});
5586
5657
5587
5658
var sfba = std.heap.stackFallback(256, astgen.arena);
5588
5659
const sfba_allocator = sfba.get();
@@ -5596,7 +5667,7 @@ fn containerDecl(
5596
5667
for (container_decl.ast.members) |member_node| {
5597
5668
if (member_node == counts.nonexhaustive_node)
5598
5669
continue;
5599
- fields_hasher .update(tree.getNodeSource(member_node));
5670
+ astgen.src_hasher .update(tree.getNodeSource(member_node));
5600
5671
var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
5601
5672
.decl => continue,
5602
5673
.field => |field| field,
@@ -5676,7 +5747,7 @@ fn containerDecl(
5676
5747
}
5677
5748
5678
5749
var fields_hash: std.zig.SrcHash = undefined;
5679
- fields_hasher .final(&fields_hash);
5750
+ astgen.src_hasher .final(&fields_hash);
5680
5751
5681
5752
const body = block_scope.instructionsSlice();
5682
5753
const body_len = astgen.countBodyLenAfterFixups(body);
@@ -8478,6 +8549,10 @@ fn tunnelThroughClosure(
8478
8549
});
8479
8550
}
8480
8551
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
8556
// Add an instruction to get the value from the closure.
8482
8557
return gz.addExtendedNodeSmall(.closure_get, inner_ref_node, cur_capture_index);
8483
8558
}
@@ -9306,6 +9381,13 @@ fn builtinCall(
9306
9381
},
9307
9382
9308
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
9391
const token_starts = tree.tokens.items(.start);
9310
9392
const node_start = token_starts[tree.firstToken(node)];
9311
9393
astgen.advanceSourceCursor(node_start);
@@ -12122,6 +12204,9 @@ const GenZir = struct {
12122
12204
is_test: bool,
12123
12205
is_extern: bool,
12124
12206
is_noinline: bool,
12207
+
12208
+ /// Ignored if `body_gz == null`.
12209
+ proto_hash: std.zig.SrcHash,
12125
12210
}) !Zir.Inst.Ref {
12126
12211
assert(args.src_node != 0);
12127
12212
const astgen = gz.astgen;
@@ -12150,15 +12235,7 @@ const GenZir = struct {
12150
12235
12151
12236
const columns = args.lbrace_column | (rbrace_column << 16);
12152
12237
12153
- const proto_hash: std.zig.SrcHash = switch (node_tags[fn_decl]) {
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);
12238
+ const proto_hash_arr: [4]u32 = @bitCast(args.proto_hash);
12162
12239
12163
12240
src_locs_and_hash_buffer = .{
12164
12241
args.lbrace_line,
0 commit comments