authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-14 17:45:21+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-03-14 17:45:21+00:00
log39459e78ad0d55ada373f9368d173040dd68d837
tree88efd4a5d646f6fb51515d1798ba52c0c7d62b54
parent5c8eda36d6de6e9858a7527af3a1e9851969189e
parent7c3237019454a6009d96eca31f36a1d9e6ce02aa
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #19273 from mlugg/incremental-some-more

compiler: more progress on incremental

6 files changed, 527 insertions(+), 178 deletions(-)

lib/std/zig/AstGen.zig+49-1
...@@ -13496,6 +13496,15 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast....@@ -13496,6 +13496,15 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.
13496 const node_tags = tree.nodes.items(.tag);13496 const node_tags = tree.nodes.items(.tag);
13497 const main_tokens = tree.nodes.items(.main_token);13497 const main_tokens = tree.nodes.items(.main_token);
13498 const token_tags = tree.tokens.items(.tag);13498 const token_tags = tree.tokens.items(.tag);
13499
13500 // We don't have shadowing for test names, so we just track those for duplicate reporting locally.
13501 var named_tests: std.AutoHashMapUnmanaged(Zir.NullTerminatedString, Ast.Node.Index) = .{};
13502 var decltests: std.AutoHashMapUnmanaged(Zir.NullTerminatedString, Ast.Node.Index) = .{};
13503 defer {
13504 named_tests.deinit(gpa);
13505 decltests.deinit(gpa);
13506 }
13507
13499 var decl_count: u32 = 0;13508 var decl_count: u32 = 0;
13500 for (members) |member_node| {13509 for (members) |member_node| {
13501 const name_token = switch (node_tags[member_node]) {13510 const name_token = switch (node_tags[member_node]) {
...@@ -13525,11 +13534,50 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast....@@ -13525,11 +13534,50 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.
13525 break :blk ident;13534 break :blk ident;
13526 },13535 },
1352713536
13528 .@"comptime", .@"usingnamespace", .test_decl => {13537 .@"comptime", .@"usingnamespace" => {
13529 decl_count += 1;13538 decl_count += 1;
13530 continue;13539 continue;
13531 },13540 },
1353213541
13542 .test_decl => {
13543 decl_count += 1;
13544 // We don't want shadowing detection here, and test names work a bit differently, so
13545 // we must do the redeclaration detection ourselves.
13546 const test_name_token = main_tokens[member_node] + 1;
13547 switch (token_tags[test_name_token]) {
13548 else => {}, // unnamed test
13549 .string_literal => {
13550 const name = try astgen.strLitAsString(test_name_token);
13551 const gop = try named_tests.getOrPut(gpa, name.index);
13552 if (gop.found_existing) {
13553 const name_slice = astgen.string_bytes.items[@intFromEnum(name.index)..][0..name.len];
13554 const name_duped = try gpa.dupe(u8, name_slice);
13555 defer gpa.free(name_duped);
13556 try astgen.appendErrorNodeNotes(member_node, "duplicate test name '{s}'", .{name_duped}, &.{
13557 try astgen.errNoteNode(gop.value_ptr.*, "other test here", .{}),
13558 });
13559 } else {
13560 gop.value_ptr.* = member_node;
13561 }
13562 },
13563 .identifier => {
13564 const name = try astgen.identAsString(test_name_token);
13565 const gop = try decltests.getOrPut(gpa, name);
13566 if (gop.found_existing) {
13567 const name_slice = mem.span(astgen.nullTerminatedString(name));
13568 const name_duped = try gpa.dupe(u8, name_slice);
13569 defer gpa.free(name_duped);
13570 try astgen.appendErrorNodeNotes(member_node, "duplicate decltest '{s}'", .{name_duped}, &.{
13571 try astgen.errNoteNode(gop.value_ptr.*, "other decltest here", .{}),
13572 });
13573 } else {
13574 gop.value_ptr.* = member_node;
13575 }
13576 },
13577 }
13578 continue;
13579 },
13580
13533 else => continue,13581 else => continue,
13534 };13582 };
1353513583
src/InternPool.zig+10-3
...@@ -67,6 +67,9 @@ src_hash_deps: std.AutoArrayHashMapUnmanaged(TrackedInst.Index, DepEntry.Index)...@@ -67,6 +67,9 @@ src_hash_deps: std.AutoArrayHashMapUnmanaged(TrackedInst.Index, DepEntry.Index)
67/// Dependencies on the value of a Decl.67/// Dependencies on the value of a Decl.
68/// Value is index into `dep_entries` of the first dependency on this Decl value.68/// Value is index into `dep_entries` of the first dependency on this Decl value.
69decl_val_deps: std.AutoArrayHashMapUnmanaged(DeclIndex, DepEntry.Index) = .{},69decl_val_deps: std.AutoArrayHashMapUnmanaged(DeclIndex, DepEntry.Index) = .{},
70/// Dependencies on the IES of a runtime function.
71/// Value is index into `dep_entries` of the first dependency on this Decl value.
72func_ies_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index) = .{},
70/// Dependencies on the full set of names in a ZIR namespace.73/// Dependencies on the full set of names in a ZIR namespace.
71/// Key refers to a `struct_decl`, `union_decl`, etc.74/// Key refers to a `struct_decl`, `union_decl`, etc.
72/// Value is index into `dep_entries` of the first dependency on this namespace.75/// Value is index into `dep_entries` of the first dependency on this namespace.
...@@ -167,6 +170,7 @@ pub const Depender = enum(u32) {...@@ -167,6 +170,7 @@ pub const Depender = enum(u32) {
167pub const Dependee = union(enum) {170pub const Dependee = union(enum) {
168 src_hash: TrackedInst.Index,171 src_hash: TrackedInst.Index,
169 decl_val: DeclIndex,172 decl_val: DeclIndex,
173 func_ies: Index,
170 namespace: TrackedInst.Index,174 namespace: TrackedInst.Index,
171 namespace_name: NamespaceNameKey,175 namespace_name: NamespaceNameKey,
172};176};
...@@ -212,6 +216,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI...@@ -212,6 +216,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI
212 const first_entry = switch (dependee) {216 const first_entry = switch (dependee) {
213 .src_hash => |x| ip.src_hash_deps.get(x),217 .src_hash => |x| ip.src_hash_deps.get(x),
214 .decl_val => |x| ip.decl_val_deps.get(x),218 .decl_val => |x| ip.decl_val_deps.get(x),
219 .func_ies => |x| ip.func_ies_deps.get(x),
215 .namespace => |x| ip.namespace_deps.get(x),220 .namespace => |x| ip.namespace_deps.get(x),
216 .namespace_name => |x| ip.namespace_name_deps.get(x),221 .namespace_name => |x| ip.namespace_name_deps.get(x),
217 } orelse return .{222 } orelse return .{
...@@ -251,6 +256,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: Depender, depend...@@ -251,6 +256,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: Depender, depend
251 const gop = try switch (tag) {256 const gop = try switch (tag) {
252 .src_hash => ip.src_hash_deps,257 .src_hash => ip.src_hash_deps,
253 .decl_val => ip.decl_val_deps,258 .decl_val => ip.decl_val_deps,
259 .func_ies => ip.func_ies_deps,
254 .namespace => ip.namespace_deps,260 .namespace => ip.namespace_deps,
255 .namespace_name => ip.namespace_name_deps,261 .namespace_name => ip.namespace_name_deps,
256 }.getOrPut(gpa, dependee_payload);262 }.getOrPut(gpa, dependee_payload);
...@@ -4324,6 +4330,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {...@@ -4324,6 +4330,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
43244330
4325 ip.src_hash_deps.deinit(gpa);4331 ip.src_hash_deps.deinit(gpa);
4326 ip.decl_val_deps.deinit(gpa);4332 ip.decl_val_deps.deinit(gpa);
4333 ip.func_ies_deps.deinit(gpa);
4327 ip.namespace_deps.deinit(gpa);4334 ip.namespace_deps.deinit(gpa);
4328 ip.namespace_name_deps.deinit(gpa);4335 ip.namespace_name_deps.deinit(gpa);
43294336
...@@ -7103,7 +7110,7 @@ pub fn getGeneratedTagEnumType(ip: *InternPool, gpa: Allocator, ini: GeneratedTa...@@ -7103,7 +7110,7 @@ pub fn getGeneratedTagEnumType(ip: *InternPool, gpa: Allocator, ini: GeneratedTa
7103 return @enumFromInt(gop.index);7110 return @enumFromInt(gop.index);
7104}7111}
71057112
7106pub const OpaqueTypeIni = struct {7113pub const OpaqueTypeInit = struct {
7107 has_namespace: bool,7114 has_namespace: bool,
7108 key: union(enum) {7115 key: union(enum) {
7109 declared: struct {7116 declared: struct {
...@@ -7117,7 +7124,7 @@ pub const OpaqueTypeIni = struct {...@@ -7117,7 +7124,7 @@ pub const OpaqueTypeIni = struct {
7117 },7124 },
7118};7125};
71197126
7120pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, ini: OpaqueTypeIni) Allocator.Error!WipNamespaceType.Result {7127pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, ini: OpaqueTypeInit) Allocator.Error!WipNamespaceType.Result {
7121 const adapter: KeyAdapter = .{ .intern_pool = ip };7128 const adapter: KeyAdapter = .{ .intern_pool = ip };
7122 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .opaque_type = switch (ini.key) {7129 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .opaque_type = switch (ini.key) {
7123 .declared => |d| .{ .declared = .{7130 .declared => |d| .{ .declared = .{
...@@ -9216,7 +9223,7 @@ pub fn funcTypeParamsLen(ip: *const InternPool, i: Index) u32 {...@@ -9216,7 +9223,7 @@ pub fn funcTypeParamsLen(ip: *const InternPool, i: Index) u32 {
9216 return ip.extra.items[start + std.meta.fieldIndex(Tag.TypeFunction, "params_len").?];9223 return ip.extra.items[start + std.meta.fieldIndex(Tag.TypeFunction, "params_len").?];
9217}9224}
92189225
9219fn unwrapCoercedFunc(ip: *const InternPool, i: Index) Index {9226pub fn unwrapCoercedFunc(ip: *const InternPool, i: Index) Index {
9220 const tags = ip.items.items(.tag);9227 const tags = ip.items.items(.tag);
9221 return switch (tags[@intFromEnum(i)]) {9228 return switch (tags[@intFromEnum(i)]) {
9222 .func_coerced => {9229 .func_coerced => {
src/Module.zig+378-137
...@@ -362,7 +362,7 @@ pub const Decl = struct {...@@ -362,7 +362,7 @@ pub const Decl = struct {
362 src_line: u32,362 src_line: u32,
363 /// Index of the ZIR `declaration` instruction from which this `Decl` was created.363 /// Index of the ZIR `declaration` instruction from which this `Decl` was created.
364 /// For the root `Decl` of a `File` and legacy anonymous decls, this is `.none`.364 /// For the root `Decl` of a `File` and legacy anonymous decls, this is `.none`.
365 zir_decl_index: Zir.Inst.OptionalIndex,365 zir_decl_index: InternPool.TrackedInst.Index.Optional,
366366
367 /// Represents the "shallow" analysis status. For example, for decls that are functions,367 /// Represents the "shallow" analysis status. For example, for decls that are functions,
368 /// the function type is analyzed with this set to `in_progress`, however, the semantic368 /// the function type is analyzed with this set to `in_progress`, however, the semantic
...@@ -428,16 +428,9 @@ pub const Decl = struct {...@@ -428,16 +428,9 @@ pub const Decl = struct {
428 const Index = InternPool.DeclIndex;428 const Index = InternPool.DeclIndex;
429 const OptionalIndex = InternPool.OptionalDeclIndex;429 const OptionalIndex = InternPool.OptionalDeclIndex;
430430
431 /// Asserts that `zir_decl_index` is not `.none`.
432 fn getDeclaration(decl: Decl, zir: Zir) Zir.Inst.Declaration {
433 const zir_index = decl.zir_decl_index.unwrap().?;
434 const pl_node = zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
435 return zir.extraData(Zir.Inst.Declaration, pl_node.payload_index).data;
436 }
437
438 pub fn zirBodies(decl: Decl, zcu: *Zcu) Zir.Inst.Declaration.Bodies {431 pub fn zirBodies(decl: Decl, zcu: *Zcu) Zir.Inst.Declaration.Bodies {
439 const zir = decl.getFileScope(zcu).zir;432 const zir = decl.getFileScope(zcu).zir;
440 const zir_index = decl.zir_decl_index.unwrap().?;433 const zir_index = decl.zir_decl_index.unwrap().?.resolve(&zcu.intern_pool);
441 const pl_node = zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;434 const pl_node = zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
442 const extra = zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);435 const extra = zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
443 return extra.data.getBodies(@intCast(extra.end), zir);436 return extra.data.getBodies(@intCast(extra.end), zir);
...@@ -769,14 +762,14 @@ pub const Namespace = struct {...@@ -769,14 +762,14 @@ pub const Namespace = struct {
769 zcu: *Zcu,762 zcu: *Zcu,
770763
771 pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 {764 pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 {
772 const decl = ctx.module.declPtr(decl_index);765 const decl = ctx.zcu.declPtr(decl_index);
773 return std.hash.uint32(@intFromEnum(decl.name));766 return std.hash.uint32(@intFromEnum(decl.name));
774 }767 }
775768
776 pub fn eql(ctx: @This(), a_decl_index: Decl.Index, b_decl_index: Decl.Index, b_index: usize) bool {769 pub fn eql(ctx: @This(), a_decl_index: Decl.Index, b_decl_index: Decl.Index, b_index: usize) bool {
777 _ = b_index;770 _ = b_index;
778 const a_decl = ctx.module.declPtr(a_decl_index);771 const a_decl = ctx.zcu.declPtr(a_decl_index);
779 const b_decl = ctx.module.declPtr(b_decl_index);772 const b_decl = ctx.zcu.declPtr(b_decl_index);
780 return a_decl.name == b_decl.name;773 return a_decl.name == b_decl.name;
781 }774 }
782 };775 };
...@@ -2662,16 +2655,15 @@ pub fn markDependeeOutdated(zcu: *Zcu, dependee: InternPool.Dependee) !void {...@@ -2662,16 +2655,15 @@ pub fn markDependeeOutdated(zcu: *Zcu, dependee: InternPool.Dependee) !void {
2662 if (opt_po_entry) |e| e.value else 0,2655 if (opt_po_entry) |e| e.value else 0,
2663 );2656 );
2664 log.debug("outdated: {}", .{depender});2657 log.debug("outdated: {}", .{depender});
2665 if (opt_po_entry != null) {2658 if (opt_po_entry == null) {
2666 // This is a new entry with no PO dependencies.2659 // This is a new entry with no PO dependencies.
2667 try zcu.outdated_ready.put(zcu.gpa, depender, {});2660 try zcu.outdated_ready.put(zcu.gpa, depender, {});
2668 }2661 }
2669 // If this is a Decl and was not previously PO, we must recursively2662 // If this is a Decl and was not previously PO, we must recursively
2670 // mark dependencies on its tyval as PO.2663 // mark dependencies on its tyval as PO.
2671 if (opt_po_entry == null) switch (depender.unwrap()) {2664 if (opt_po_entry == null) {
2672 .decl => |decl_index| try zcu.markDeclDependenciesPotentiallyOutdated(decl_index),2665 try zcu.markTransitiveDependersPotentiallyOutdated(depender);
2673 .func => {},2666 }
2674 };
2675 }2667 }
2676}2668}
26772669
...@@ -2701,15 +2693,19 @@ fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {...@@ -2701,15 +2693,19 @@ fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
2701 // as no longer PO.2693 // as no longer PO.
2702 switch (depender.unwrap()) {2694 switch (depender.unwrap()) {
2703 .decl => |decl_index| try zcu.markPoDependeeUpToDate(.{ .decl_val = decl_index }),2695 .decl => |decl_index| try zcu.markPoDependeeUpToDate(.{ .decl_val = decl_index }),
2704 .func => {},2696 .func => |func_index| try zcu.markPoDependeeUpToDate(.{ .func_ies = func_index }),
2705 }2697 }
2706 }2698 }
2707}2699}
27082700
2709/// Given a Decl which is newly outdated or PO, mark all dependers which depend2701/// Given a Depender which is newly outdated or PO, mark all Dependers which may
2710/// on its tyval as PO.2702/// in turn be PO, due to a dependency on the original Depender's tyval or IES.
2711fn markDeclDependenciesPotentiallyOutdated(zcu: *Zcu, decl_index: Decl.Index) !void {2703fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: InternPool.Depender) !void {
2712 var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index });2704 var it = zcu.intern_pool.dependencyIterator(switch (maybe_outdated.unwrap()) {
2705 .decl => |decl_index| .{ .decl_val = decl_index }, // TODO: also `decl_ref` deps when introduced
2706 .func => |func_index| .{ .func_ies = func_index },
2707 });
2708
2713 while (it.next()) |po| {2709 while (it.next()) |po| {
2714 if (zcu.outdated.getPtr(po)) |po_dep_count| {2710 if (zcu.outdated.getPtr(po)) |po_dep_count| {
2715 // This dependency is already outdated, but it now has one more PO2711 // This dependency is already outdated, but it now has one more PO
...@@ -2726,14 +2722,9 @@ fn markDeclDependenciesPotentiallyOutdated(zcu: *Zcu, decl_index: Decl.Index) !v...@@ -2726,14 +2722,9 @@ fn markDeclDependenciesPotentiallyOutdated(zcu: *Zcu, decl_index: Decl.Index) !v
2726 continue;2722 continue;
2727 }2723 }
2728 try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1);2724 try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1);
2729 // If this ia a Decl, we must recursively mark dependencies2725 // This Depender was not already PO, so we must recursively mark its dependers as also PO.
2730 // on its tyval as PO.2726 try zcu.markTransitiveDependersPotentiallyOutdated(po);
2731 switch (po.unwrap()) {
2732 .decl => |po_decl| try zcu.markDeclDependenciesPotentiallyOutdated(po_decl),
2733 .func => {},
2734 }
2735 }2727 }
2736 // TODO: repeat the above for `decl_ty` dependencies when they are introduced
2737}2728}
27382729
2739pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.Depender {2730pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.Depender {
...@@ -2859,10 +2850,7 @@ pub fn flushRetryableFailures(zcu: *Zcu) !void {...@@ -2859,10 +2850,7 @@ pub fn flushRetryableFailures(zcu: *Zcu) !void {
2859 // This Depender was not marked PO, but is now outdated. Mark it as2850 // This Depender was not marked PO, but is now outdated. Mark it as
2860 // such, then recursively mark transitive dependencies as PO.2851 // such, then recursively mark transitive dependencies as PO.
2861 try zcu.outdated.put(gpa, depender, 0);2852 try zcu.outdated.put(gpa, depender, 0);
2862 switch (depender.unwrap()) {2853 try zcu.markTransitiveDependersPotentiallyOutdated(depender);
2863 .decl => |decl| try zcu.markDeclDependenciesPotentiallyOutdated(decl),
2864 .func => {},
2865 }
2866 }2854 }
2867 zcu.retryable_failures.clearRetainingCapacity();2855 zcu.retryable_failures.clearRetainingCapacity();
2868}2856}
...@@ -2994,6 +2982,15 @@ pub fn mapOldZirToNew(...@@ -2994,6 +2982,15 @@ pub fn mapOldZirToNew(
2994 }2982 }
2995}2983}
29962984
2985/// Like `ensureDeclAnalyzed`, but the Decl is a file's root Decl.
2986pub fn ensureFileAnalyzed(zcu: *Zcu, file: *File) SemaError!void {
2987 if (file.root_decl.unwrap()) |existing_root| {
2988 return zcu.ensureDeclAnalyzed(existing_root);
2989 } else {
2990 return zcu.semaFile(file);
2991 }
2992}
2993
2997/// This ensures that the Decl will have an up-to-date Type and Value populated.2994/// This ensures that the Decl will have an up-to-date Type and Value populated.
2998/// However the resolution status of the Type may not be fully resolved.2995/// However the resolution status of the Type may not be fully resolved.
2999/// For example an inferred error set is not resolved until after `analyzeFnBody`.2996/// For example an inferred error set is not resolved until after `analyzeFnBody`.
...@@ -3004,6 +3001,11 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -3004,6 +3001,11 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
30043001
3005 const decl = mod.declPtr(decl_index);3002 const decl = mod.declPtr(decl_index);
30063003
3004 log.debug("ensureDeclAnalyzed '{d}' (name '{}')", .{
3005 @intFromEnum(decl_index),
3006 decl.name.fmt(&mod.intern_pool),
3007 });
3008
3007 // Determine whether or not this Decl is outdated, i.e. requires re-analysis3009 // Determine whether or not this Decl is outdated, i.e. requires re-analysis
3008 // even if `complete`. If a Decl is PO, we pessismistically assume that it3010 // even if `complete`. If a Decl is PO, we pessismistically assume that it
3009 // *does* require re-analysis, to ensure that the Decl is definitely3011 // *does* require re-analysis, to ensure that the Decl is definitely
...@@ -3015,13 +3017,15 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -3015,13 +3017,15 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
3015 // dependencies are all up-to-date.3017 // dependencies are all up-to-date.
30163018
3017 const decl_as_depender = InternPool.Depender.wrap(.{ .decl = decl_index });3019 const decl_as_depender = InternPool.Depender.wrap(.{ .decl = decl_index });
3018 const was_outdated = mod.outdated.swapRemove(decl_as_depender) or3020 const decl_was_outdated = mod.outdated.swapRemove(decl_as_depender) or
3019 mod.potentially_outdated.swapRemove(decl_as_depender);3021 mod.potentially_outdated.swapRemove(decl_as_depender);
30203022
3021 if (was_outdated) {3023 if (decl_was_outdated) {
3022 _ = mod.outdated_ready.swapRemove(decl_as_depender);3024 _ = mod.outdated_ready.swapRemove(decl_as_depender);
3023 }3025 }
30243026
3027 const was_outdated = mod.outdated_file_root.swapRemove(decl_index) or decl_was_outdated;
3028
3025 switch (decl.analysis) {3029 switch (decl.analysis) {
3026 .in_progress => unreachable,3030 .in_progress => unreachable,
30273031
...@@ -3057,6 +3061,14 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -3057,6 +3061,14 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
3057 };3061 };
3058 }3062 }
30593063
3064 if (mod.declIsRoot(decl_index)) {
3065 const changed = try mod.semaFileUpdate(decl.getFileScope(mod), decl_was_outdated);
3066 break :blk .{
3067 .invalidate_decl_val = changed,
3068 .invalidate_decl_ref = changed,
3069 };
3070 }
3071
3060 break :blk mod.semaDecl(decl_index) catch |err| switch (err) {3072 break :blk mod.semaDecl(decl_index) catch |err| switch (err) {
3061 error.AnalysisFail => {3073 error.AnalysisFail => {
3062 if (decl.analysis == .in_progress) {3074 if (decl.analysis == .in_progress) {
...@@ -3085,13 +3097,15 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -3085,13 +3097,15 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
3085 };3097 };
30863098
3087 // TODO: we do not yet have separate dependencies for decl values vs types.3099 // TODO: we do not yet have separate dependencies for decl values vs types.
3088 if (was_outdated) {3100 if (decl_was_outdated) {
3089 if (sema_result.invalidate_decl_val or sema_result.invalidate_decl_ref) {3101 if (sema_result.invalidate_decl_val or sema_result.invalidate_decl_ref) {
3102 log.debug("Decl tv invalidated ('{d}')", .{@intFromEnum(decl_index)});
3090 // This dependency was marked as PO, meaning dependees were waiting3103 // This dependency was marked as PO, meaning dependees were waiting
3091 // on its analysis result, and it has turned out to be outdated.3104 // on its analysis result, and it has turned out to be outdated.
3092 // Update dependees accordingly.3105 // Update dependees accordingly.
3093 try mod.markDependeeOutdated(.{ .decl_val = decl_index });3106 try mod.markDependeeOutdated(.{ .decl_val = decl_index });
3094 } else {3107 } else {
3108 log.debug("Decl tv up-to-date ('{d}')", .{@intFromEnum(decl_index)});
3095 // This dependency was previously PO, but turned out to be up-to-date.3109 // This dependency was previously PO, but turned out to be up-to-date.
3096 // We do not need to queue successive analysis.3110 // We do not need to queue successive analysis.
3097 try mod.markPoDependeeUpToDate(.{ .decl_val = decl_index });3111 try mod.markPoDependeeUpToDate(.{ .decl_val = decl_index });
...@@ -3099,15 +3113,48 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -3099,15 +3113,48 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
3099 }3113 }
3100}3114}
31013115
3102pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError!void {3116pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.Index) SemaError!void {
3103 const tracy = trace(@src());3117 const tracy = trace(@src());
3104 defer tracy.end();3118 defer tracy.end();
31053119
3120 const gpa = zcu.gpa;
3106 const ip = &zcu.intern_pool;3121 const ip = &zcu.intern_pool;
3107 const func = zcu.funcInfo(func_index);3122
3123 // We only care about the uncoerced function.
3124 // We need to do this for the "orphaned function" check below to be valid.
3125 const func_index = ip.unwrapCoercedFunc(maybe_coerced_func_index);
3126
3127 const func = zcu.funcInfo(maybe_coerced_func_index);
3108 const decl_index = func.owner_decl;3128 const decl_index = func.owner_decl;
3109 const decl = zcu.declPtr(decl_index);3129 const decl = zcu.declPtr(decl_index);
31103130
3131 log.debug("ensureFuncBodyAnalyzed '{d}' (instance of '{}')", .{
3132 @intFromEnum(func_index),
3133 decl.name.fmt(ip),
3134 });
3135
3136 // First, our owner decl must be up-to-date. This will always be the case
3137 // during the first update, but may not on successive updates if we happen
3138 // to get analyzed before our parent decl.
3139 try zcu.ensureDeclAnalyzed(decl_index);
3140
3141 // On an update, it's possible this function changed such that our owner
3142 // decl now refers to a different function, making this one orphaned. If
3143 // that's the case, we should remove this function from the binary.
3144 if (decl.val.ip_index != func_index) {
3145 try zcu.markDependeeOutdated(.{ .func_ies = func_index });
3146 ip.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index }));
3147 ip.remove(func_index);
3148 @panic("TODO: remove orphaned function from binary");
3149 }
3150
3151 // We'll want to remember what the IES used to be before the update for
3152 // dependency invalidation purposes.
3153 const old_resolved_ies = if (func.analysis(ip).inferred_error_set)
3154 func.resolvedErrorSet(ip).*
3155 else
3156 .none;
3157
3111 switch (decl.analysis) {3158 switch (decl.analysis) {
3112 .unreferenced => unreachable,3159 .unreferenced => unreachable,
3113 .in_progress => unreachable,3160 .in_progress => unreachable,
...@@ -3131,7 +3178,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError...@@ -3131,7 +3178,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError
3131 }3178 }
31323179
3133 switch (func.analysis(ip).state) {3180 switch (func.analysis(ip).state) {
3134 .success,3181 .success => if (!was_outdated) return,
3135 .sema_failure,3182 .sema_failure,
3136 .dependency_failure,3183 .dependency_failure,
3137 .codegen_failure,3184 .codegen_failure,
...@@ -3141,7 +3188,10 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError...@@ -3141,7 +3188,10 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError
3141 .inline_only => unreachable, // don't queue work for this3188 .inline_only => unreachable, // don't queue work for this
3142 }3189 }
31433190
3144 const gpa = zcu.gpa;3191 log.debug("analyze and generate fn body '{d}'; reason='{s}'", .{
3192 @intFromEnum(func_index),
3193 if (was_outdated) "outdated" else "never analyzed",
3194 });
31453195
3146 var tmp_arena = std.heap.ArenaAllocator.init(gpa);3196 var tmp_arena = std.heap.ArenaAllocator.init(gpa);
3147 defer tmp_arena.deinit();3197 defer tmp_arena.deinit();
...@@ -3161,6 +3211,20 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError...@@ -3161,6 +3211,20 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError
3161 };3211 };
3162 defer air.deinit(gpa);3212 defer air.deinit(gpa);
31633213
3214 const invalidate_ies_deps = i: {
3215 if (!was_outdated) break :i false;
3216 if (!func.analysis(ip).inferred_error_set) break :i true;
3217 const new_resolved_ies = func.resolvedErrorSet(ip).*;
3218 break :i new_resolved_ies != old_resolved_ies;
3219 };
3220 if (invalidate_ies_deps) {
3221 log.debug("func IES invalidated ('{d}')", .{@intFromEnum(func_index)});
3222 try zcu.markDependeeOutdated(.{ .func_ies = func_index });
3223 } else if (was_outdated) {
3224 log.debug("func IES up-to-date ('{d}')", .{@intFromEnum(func_index)});
3225 try zcu.markPoDependeeUpToDate(.{ .func_ies = func_index });
3226 }
3227
3164 const comp = zcu.comp;3228 const comp = zcu.comp;
31653229
3166 const dump_air = build_options.enable_debug_extensions and comp.verbose_air;3230 const dump_air = build_options.enable_debug_extensions and comp.verbose_air;
...@@ -3299,7 +3363,9 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)...@@ -3299,7 +3363,9 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)
3299/// https://github.com/ziglang/zig/issues/143073363/// https://github.com/ziglang/zig/issues/14307
3300pub fn semaPkg(mod: *Module, pkg: *Package.Module) !void {3364pub fn semaPkg(mod: *Module, pkg: *Package.Module) !void {
3301 const file = (try mod.importPkg(pkg)).file;3365 const file = (try mod.importPkg(pkg)).file;
3302 return mod.semaFile(file);3366 if (file.root_decl == .none) {
3367 return mod.semaFile(file);
3368 }
3303}3369}
33043370
3305fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespace.Index, file: *File) Allocator.Error!InternPool.Index {3371fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespace.Index, file: *File) Allocator.Error!InternPool.Index {
...@@ -3366,13 +3432,75 @@ fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespa...@@ -3366,13 +3432,75 @@ fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespa
3366 return wip_ty.finish(ip, decl_index, namespace_index.toOptional());3432 return wip_ty.finish(ip, decl_index, namespace_index.toOptional());
3367}3433}
33683434
3369/// Regardless of the file status, will create a `Decl` so that we3435/// Re-analyze the root Decl of a file on an incremental update.
3370/// can track dependencies and re-analyze when the file becomes outdated.3436/// If `type_outdated`, the struct type itself is considered outdated and is
3371pub fn semaFile(mod: *Module, file: *File) SemaError!void {3437/// reconstructed at a new InternPool index. Otherwise, the namespace is just
3438/// re-analyzed. Returns whether the decl's tyval was invalidated.
3439fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {
3440 const decl = zcu.declPtr(file.root_decl.unwrap().?);
3441
3442 log.debug("semaFileUpdate mod={s} sub_file_path={s} type_outdated={}", .{
3443 file.mod.fully_qualified_name,
3444 file.sub_file_path,
3445 type_outdated,
3446 });
3447
3448 if (file.status != .success_zir) {
3449 if (decl.analysis == .file_failure) {
3450 return false;
3451 } else {
3452 decl.analysis = .file_failure;
3453 return true;
3454 }
3455 }
3456
3457 if (decl.analysis == .file_failure) {
3458 // No struct type currently exists. Create one!
3459 _ = try zcu.getFileRootStruct(file.root_decl.unwrap().?, decl.src_namespace, file);
3460 return true;
3461 }
3462
3463 assert(decl.has_tv);
3464 assert(decl.owns_tv);
3465
3466 if (type_outdated) {
3467 // Invalidate the existing type, reusing the decl and namespace.
3468 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.Depender.wrap(.{ .decl = file.root_decl.unwrap().? }));
3469 zcu.intern_pool.remove(decl.val.toIntern());
3470 decl.val = undefined;
3471 _ = try zcu.getFileRootStruct(file.root_decl.unwrap().?, decl.src_namespace, file);
3472 return true;
3473 }
3474
3475 // Only the struct's namespace is outdated.
3476 // Preserve the type - just scan the namespace again.
3477
3478 const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
3479 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3480
3481 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
3482 extra_index += @intFromBool(small.has_fields_len);
3483 const decls_len = if (small.has_decls_len) blk: {
3484 const decls_len = file.zir.extra[extra_index];
3485 extra_index += 1;
3486 break :blk decls_len;
3487 } else 0;
3488 const decls = file.zir.bodySlice(extra_index, decls_len);
3489
3490 if (!type_outdated) {
3491 try zcu.scanNamespace(decl.src_namespace, decls, decl);
3492 }
3493
3494 return false;
3495}
3496
3497/// Regardless of the file status, will create a `Decl` if none exists so that we can track
3498/// dependencies and re-analyze when the file becomes outdated.
3499fn semaFile(mod: *Module, file: *File) SemaError!void {
3372 const tracy = trace(@src());3500 const tracy = trace(@src());
3373 defer tracy.end();3501 defer tracy.end();
33743502
3375 if (file.root_decl != .none) return;3503 assert(file.root_decl == .none);
33763504
3377 const gpa = mod.gpa;3505 const gpa = mod.gpa;
3378 log.debug("semaFile mod={s} sub_file_path={s}", .{3506 log.debug("semaFile mod={s} sub_file_path={s}", .{
...@@ -3439,9 +3567,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -3439,9 +3567,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
3439 },3567 },
3440 .incremental => {},3568 .incremental => {},
3441 }3569 }
3442
3443 // Since this is our first time analyzing this file, there can be no dependencies on
3444 // its root Decl. Thus, we do not need to invalidate any dependencies.
3445}3570}
34463571
3447const SemaDeclResult = packed struct {3572const SemaDeclResult = packed struct {
...@@ -3462,16 +3587,16 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {...@@ -3462,16 +3587,16 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
3462 return error.AnalysisFail;3587 return error.AnalysisFail;
3463 }3588 }
34643589
3465 if (mod.declIsRoot(decl_index)) {3590 assert(!mod.declIsRoot(decl_index));
3466 // This comes from an `analyze_decl` job on an incremental update where3591
3467 // this file changed.3592 if (decl.zir_decl_index == .none and decl.owns_tv) {
3468 @panic("TODO: update root Decl of modified file");3593 // We are re-analyzing an anonymous owner Decl (for a function or a namespace type).
3469 } else if (decl.owns_tv) {3594 return mod.semaAnonOwnerDecl(decl_index);
3470 // We are re-analyzing an owner Decl (for a function or a namespace type).
3471 @panic("TODO: update owner Decl");
3472 }3595 }
34733596
3474 const decl_inst = decl.zir_decl_index.unwrap().?;3597 log.debug("semaDecl '{d}'", .{@intFromEnum(decl_index)});
3598
3599 const decl_inst = decl.zir_decl_index.unwrap().?.resolve(ip);
34753600
3476 const gpa = mod.gpa;3601 const gpa = mod.gpa;
3477 const zir = decl.getFileScope(mod).zir;3602 const zir = decl.getFileScope(mod).zir;
...@@ -3763,6 +3888,42 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {...@@ -3763,6 +3888,42 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
3763 return result;3888 return result;
3764}3889}
37653890
3891fn semaAnonOwnerDecl(zcu: *Zcu, decl_index: Decl.Index) !SemaDeclResult {
3892 const decl = zcu.declPtr(decl_index);
3893
3894 assert(decl.has_tv);
3895 assert(decl.owns_tv);
3896
3897 log.debug("semaAnonOwnerDecl '{d}'", .{@intFromEnum(decl_index)});
3898
3899 switch (decl.ty.zigTypeTag(zcu)) {
3900 .Fn => @panic("TODO: update fn instance"),
3901 .Type => {},
3902 else => unreachable,
3903 }
3904
3905 // We are the owner Decl of a type, and we were marked as outdated. That means the *structure*
3906 // of this type changed; not just its namespace. Therefore, we need a new InternPool index.
3907 //
3908 // However, as soon as we make that, the context that created us will require re-analysis anyway
3909 // (as it depends on this Decl's value), meaning the `struct_decl` (or equivalent) instruction
3910 // will be analyzed again. Since Sema already needs to be able to reconstruct types like this,
3911 // why should we bother implementing it here too when the Sema logic will be hit right after?
3912 //
3913 // So instead, let's just mark this Decl as failed - so that any remaining Decls which genuinely
3914 // reference it (via `@This`) end up silently erroring too - and we'll let Sema make a new type
3915 // with a new Decl.
3916 //
3917 // Yes, this does mean that any type owner Decl has a constant value for its entire lifetime.
3918 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
3919 zcu.intern_pool.remove(decl.val.toIntern());
3920 decl.analysis = .dependency_failure;
3921 return .{
3922 .invalidate_decl_val = true,
3923 .invalidate_decl_ref = true,
3924 };
3925}
3926
3766pub const ImportFileResult = struct {3927pub const ImportFileResult = struct {
3767 file: *File,3928 file: *File,
3768 is_new: bool,3929 is_new: bool,
...@@ -4083,26 +4244,87 @@ pub fn scanNamespace(...@@ -4083,26 +4244,87 @@ pub fn scanNamespace(
4083 const gpa = zcu.gpa;4244 const gpa = zcu.gpa;
4084 const namespace = zcu.namespacePtr(namespace_index);4245 const namespace = zcu.namespacePtr(namespace_index);
40854246
4247 // For incremental updates, `scanDecl` wants to look up existing decls by their ZIR index rather
4248 // than their name. We'll build an efficient mapping now, then discard the current `decls`.
4249 var existing_by_inst: std.AutoHashMapUnmanaged(InternPool.TrackedInst.Index, Decl.Index) = .{};
4250 defer existing_by_inst.deinit(gpa);
4251
4252 try existing_by_inst.ensureTotalCapacity(gpa, @intCast(namespace.decls.count()));
4253
4254 for (namespace.decls.keys()) |decl_index| {
4255 const decl = zcu.declPtr(decl_index);
4256 existing_by_inst.putAssumeCapacityNoClobber(decl.zir_decl_index.unwrap().?, decl_index);
4257 }
4258
4259 var seen_decls: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
4260 defer seen_decls.deinit(gpa);
4261
4086 try zcu.comp.work_queue.ensureUnusedCapacity(decls.len);4262 try zcu.comp.work_queue.ensureUnusedCapacity(decls.len);
4263
4264 namespace.decls.clearRetainingCapacity();
4087 try namespace.decls.ensureTotalCapacity(gpa, decls.len);4265 try namespace.decls.ensureTotalCapacity(gpa, decls.len);
40884266
4267 namespace.usingnamespace_set.clearRetainingCapacity();
4268
4089 var scan_decl_iter: ScanDeclIter = .{4269 var scan_decl_iter: ScanDeclIter = .{
4090 .zcu = zcu,4270 .zcu = zcu,
4091 .namespace_index = namespace_index,4271 .namespace_index = namespace_index,
4092 .parent_decl = parent_decl,4272 .parent_decl = parent_decl,
4273 .seen_decls = &seen_decls,
4274 .existing_by_inst = &existing_by_inst,
4275 .pass = .named,
4093 };4276 };
4094 for (decls) |decl_inst| {4277 for (decls) |decl_inst| {
4095 try scanDecl(&scan_decl_iter, decl_inst);4278 try scanDecl(&scan_decl_iter, decl_inst);
4096 }4279 }
4280 scan_decl_iter.pass = .unnamed;
4281 for (decls) |decl_inst| {
4282 try scanDecl(&scan_decl_iter, decl_inst);
4283 }
4284
4285 if (seen_decls.count() != namespace.decls.count()) {
4286 // Do a pass over the namespace contents and remove any decls from the last update
4287 // which were removed in this one.
4288 var i: usize = 0;
4289 while (i < namespace.decls.count()) {
4290 const decl_index = namespace.decls.keys()[i];
4291 const decl = zcu.declPtr(decl_index);
4292 if (!seen_decls.contains(decl.name)) {
4293 // We must preserve namespace ordering for @typeInfo.
4294 namespace.decls.orderedRemoveAt(i);
4295 i -= 1;
4296 }
4297 }
4298 }
4097}4299}
40984300
4099const ScanDeclIter = struct {4301const ScanDeclIter = struct {
4100 zcu: *Zcu,4302 zcu: *Zcu,
4101 namespace_index: Namespace.Index,4303 namespace_index: Namespace.Index,
4102 parent_decl: *Decl,4304 parent_decl: *Decl,
4305 seen_decls: *std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),
4306 existing_by_inst: *const std.AutoHashMapUnmanaged(InternPool.TrackedInst.Index, Decl.Index),
4307 /// Decl scanning is run in two passes, so that we can detect when a generated
4308 /// name would clash with an explicit name and use a different one.
4309 pass: enum { named, unnamed },
4103 usingnamespace_index: usize = 0,4310 usingnamespace_index: usize = 0,
4104 comptime_index: usize = 0,4311 comptime_index: usize = 0,
4105 unnamed_test_index: usize = 0,4312 unnamed_test_index: usize = 0,
4313
4314 fn avoidNameConflict(iter: *ScanDeclIter, comptime fmt: []const u8, args: anytype) !InternPool.NullTerminatedString {
4315 const zcu = iter.zcu;
4316 const gpa = zcu.gpa;
4317 const ip = &zcu.intern_pool;
4318 var name = try ip.getOrPutStringFmt(gpa, fmt, args);
4319 var gop = try iter.seen_decls.getOrPut(gpa, name);
4320 var next_suffix: u32 = 0;
4321 while (gop.found_existing) {
4322 name = try ip.getOrPutStringFmt(gpa, fmt ++ "_{d}", args ++ .{next_suffix});
4323 gop = try iter.seen_decls.getOrPut(gpa, name);
4324 next_suffix += 1;
4325 }
4326 return name;
4327 }
4106};4328};
41074329
4108fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void {4330fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void {
...@@ -4126,134 +4348,148 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void...@@ -4126,134 +4348,148 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void
4126 // Every Decl needs a name.4348 // Every Decl needs a name.
4127 const decl_name: InternPool.NullTerminatedString, const kind: Decl.Kind, const is_named_test: bool = switch (declaration.name) {4349 const decl_name: InternPool.NullTerminatedString, const kind: Decl.Kind, const is_named_test: bool = switch (declaration.name) {
4128 .@"comptime" => info: {4350 .@"comptime" => info: {
4351 if (iter.pass != .unnamed) return;
4129 const i = iter.comptime_index;4352 const i = iter.comptime_index;
4130 iter.comptime_index += 1;4353 iter.comptime_index += 1;
4131 break :info .{4354 break :info .{
4132 try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i}),4355 try iter.avoidNameConflict("comptime_{d}", .{i}),
4133 .@"comptime",4356 .@"comptime",
4134 false,4357 false,
4135 };4358 };
4136 },4359 },
4137 .@"usingnamespace" => info: {4360 .@"usingnamespace" => info: {
4361 // TODO: this isn't right! These should be considered unnamed. Name conflicts can happen here.
4362 // The problem is, we need to preserve the decl ordering for `@typeInfo`.
4363 // I'm not bothering to fix this now, since some upcoming changes will change this code significantly anyway.
4364 if (iter.pass != .named) return;
4138 const i = iter.usingnamespace_index;4365 const i = iter.usingnamespace_index;
4139 iter.usingnamespace_index += 1;4366 iter.usingnamespace_index += 1;
4140 break :info .{4367 break :info .{
4141 try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i}),4368 try iter.avoidNameConflict("usingnamespace_{d}", .{i}),
4142 .@"usingnamespace",4369 .@"usingnamespace",
4143 false,4370 false,
4144 };4371 };
4145 },4372 },
4146 .unnamed_test => info: {4373 .unnamed_test => info: {
4374 if (iter.pass != .unnamed) return;
4147 const i = iter.unnamed_test_index;4375 const i = iter.unnamed_test_index;
4148 iter.unnamed_test_index += 1;4376 iter.unnamed_test_index += 1;
4149 break :info .{4377 break :info .{
4150 try ip.getOrPutStringFmt(gpa, "test_{d}", .{i}),4378 try iter.avoidNameConflict("test_{d}", .{i}),
4151 .@"test",4379 .@"test",
4152 false,4380 false,
4153 };4381 };
4154 },4382 },
4155 .decltest => info: {4383 .decltest => info: {
4384 // We consider these to be unnamed since the decl name can be adjusted to avoid conflicts if necessary.
4385 if (iter.pass != .unnamed) return;
4156 assert(declaration.flags.has_doc_comment);4386 assert(declaration.flags.has_doc_comment);
4157 const name = zir.nullTerminatedString(@enumFromInt(zir.extra[extra.end]));4387 const name = zir.nullTerminatedString(@enumFromInt(zir.extra[extra.end]));
4158 break :info .{4388 break :info .{
4159 try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{name}),4389 try iter.avoidNameConflict("decltest.{s}", .{name}),
4160 .@"test",4390 .@"test",
4161 true,4391 true,
4162 };4392 };
4163 },4393 },
4164 _ => if (declaration.name.isNamedTest(zir)) .{4394 _ => if (declaration.name.isNamedTest(zir)) info: {
4165 try ip.getOrPutStringFmt(gpa, "test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}),4395 // We consider these to be unnamed since the decl name can be adjusted to avoid conflicts if necessary.
4166 .@"test",4396 if (iter.pass != .unnamed) return;
4167 true,4397 break :info .{
4168 } else .{4398 try iter.avoidNameConflict("test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}),
4169 try ip.getOrPutString(gpa, zir.nullTerminatedString(declaration.name.toString(zir).?)),4399 .@"test",
4170 .named,4400 true,
4171 false,4401 };
4402 } else info: {
4403 if (iter.pass != .named) return;
4404 const name = try ip.getOrPutString(gpa, zir.nullTerminatedString(declaration.name.toString(zir).?));
4405 try iter.seen_decls.putNoClobber(gpa, name, {});
4406 break :info .{
4407 name,
4408 .named,
4409 false,
4410 };
4172 },4411 },
4173 };4412 };
41744413
4175 if (kind == .@"usingnamespace") try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1);4414 switch (kind) {
4415 .@"usingnamespace" => try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1),
4416 .@"test" => try zcu.test_functions.ensureUnusedCapacity(gpa, 1),
4417 else => {},
4418 }
4419
4420 const tracked_inst = try ip.trackZir(gpa, iter.parent_decl.getFileScope(zcu), decl_inst);
41764421
4177 // We create a Decl for it regardless of analysis status.4422 // We create a Decl for it regardless of analysis status.
4178 const gop = try namespace.decls.getOrPutContextAdapted(4423
4179 gpa,4424 const prev_exported, const decl_index = if (iter.existing_by_inst.get(tracked_inst)) |decl_index| decl_index: {
4180 decl_name,4425 // We need only update this existing Decl.
4181 DeclAdapter{ .zcu = zcu },4426 const decl = zcu.declPtr(decl_index);
4182 Namespace.DeclContext{ .zcu = zcu },4427 const was_exported = decl.is_exported;
4183 );4428 assert(decl.kind == kind); // ZIR tracking should preserve this
4184 const comp = zcu.comp;4429 assert(decl.alive);
4185 if (!gop.found_existing) {4430 decl.name = decl_name;
4431 decl.src_node = decl_node;
4432 decl.src_line = line;
4433 decl.is_pub = declaration.flags.is_pub;
4434 decl.is_exported = declaration.flags.is_export;
4435 break :decl_index .{ was_exported, decl_index };
4436 } else decl_index: {
4437 // Create and set up a new Decl.
4186 const new_decl_index = try zcu.allocateNewDecl(namespace_index, decl_node);4438 const new_decl_index = try zcu.allocateNewDecl(namespace_index, decl_node);
4187 const new_decl = zcu.declPtr(new_decl_index);4439 const new_decl = zcu.declPtr(new_decl_index);
4188 new_decl.kind = kind;4440 new_decl.kind = kind;
4189 new_decl.name = decl_name;4441 new_decl.name = decl_name;
4190 if (kind == .@"usingnamespace") {
4191 namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, declaration.flags.is_pub);
4192 }
4193 new_decl.src_line = line;4442 new_decl.src_line = line;
4194 gop.key_ptr.* = new_decl_index;
4195 // Exported decls, comptime decls, usingnamespace decls, and
4196 // test decls if in test mode, get analyzed.
4197 const decl_mod = namespace.file_scope.mod;
4198 const want_analysis = declaration.flags.is_export or switch (kind) {
4199 .anon => unreachable,
4200 .@"comptime", .@"usingnamespace" => true,
4201 .named => false,
4202 .@"test" => a: {
4203 if (!comp.config.is_test) break :a false;
4204 if (decl_mod != zcu.main_mod) break :a false;
4205 if (is_named_test and comp.test_filters.len > 0) {
4206 const decl_fqn = ip.stringToSlice(try namespace.fullyQualifiedName(zcu, decl_name));
4207 for (comp.test_filters) |test_filter| {
4208 if (mem.indexOf(u8, decl_fqn, test_filter)) |_| break;
4209 } else break :a false;
4210 }
4211 try zcu.test_functions.put(gpa, new_decl_index, {});
4212 break :a true;
4213 },
4214 };
4215 if (want_analysis) {
4216 log.debug("scanDecl queue analyze_decl file='{s}' decl_name='{s}' decl_index={d}", .{
4217 namespace.file_scope.sub_file_path, ip.stringToSlice(decl_name), new_decl_index,
4218 });
4219 comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl_index });
4220 }
4221 new_decl.is_pub = declaration.flags.is_pub;4443 new_decl.is_pub = declaration.flags.is_pub;
4222 new_decl.is_exported = declaration.flags.is_export;4444 new_decl.is_exported = declaration.flags.is_export;
4223 new_decl.zir_decl_index = decl_inst.toOptional();4445 new_decl.zir_decl_index = tracked_inst.toOptional();
4224 new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive.4446 new_decl.alive = true; // This Decl corresponds to an AST node and is therefore always alive.
4225 return;4447 break :decl_index .{ false, new_decl_index };
4226 }4448 };
4227 const decl_index = gop.key_ptr.*;4449
4228 const decl = zcu.declPtr(decl_index);4450 const decl = zcu.declPtr(decl_index);
4229 if (kind == .@"test") {4451
4230 const src_loc = SrcLoc{4452 namespace.decls.putAssumeCapacityNoClobberContext(decl_index, {}, .{ .zcu = zcu });
4231 .file_scope = decl.getFileScope(zcu),4453
4232 .parent_decl_node = decl.src_node,4454 const comp = zcu.comp;
4233 .lazy = .{ .token_offset = 1 },4455 const decl_mod = namespace.file_scope.mod;
4234 };4456 const want_analysis = declaration.flags.is_export or switch (kind) {
4235 const msg = try ErrorMsg.create(gpa, src_loc, "duplicate test name: {}", .{4457 .anon => unreachable,
4236 decl_name.fmt(ip),4458 .@"comptime" => true,
4237 });4459 .@"usingnamespace" => a: {
4238 errdefer msg.destroy(gpa);4460 namespace.usingnamespace_set.putAssumeCapacityNoClobber(decl_index, declaration.flags.is_pub);
4239 try zcu.failed_decls.putNoClobber(gpa, decl_index, msg);4461 break :a true;
4240 const other_src_loc = SrcLoc{4462 },
4241 .file_scope = namespace.file_scope,4463 .named => false,
4242 .parent_decl_node = decl_node,4464 .@"test" => a: {
4243 .lazy = .{ .token_offset = 1 },4465 if (!comp.config.is_test) break :a false;
4244 };4466 if (decl_mod != zcu.main_mod) break :a false;
4245 try zcu.errNoteNonLazy(other_src_loc, msg, "other test here", .{});4467 if (is_named_test and comp.test_filters.len > 0) {
4468 const decl_fqn = ip.stringToSlice(try namespace.fullyQualifiedName(zcu, decl_name));
4469 for (comp.test_filters) |test_filter| {
4470 if (mem.indexOf(u8, decl_fqn, test_filter)) |_| break;
4471 } else break :a false;
4472 }
4473 zcu.test_functions.putAssumeCapacity(decl_index, {}); // may clobber on incremental update
4474 break :a true;
4475 },
4476 };
4477
4478 if (want_analysis) {
4479 // We will not queue analysis if the decl has been analyzed on a previous update and
4480 // `is_export` is unchanged. In this case, the incremental update mechanism will handle
4481 // re-analysis for us if necessary.
4482 if (prev_exported != declaration.flags.is_export or decl.analysis == .unreferenced) {
4483 log.debug("scanDecl queue analyze_decl file='{s}' decl_name='{s}' decl_index={d}", .{
4484 namespace.file_scope.sub_file_path, ip.stringToSlice(decl_name), decl_index,
4485 });
4486 comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = decl_index });
4487 }
4246 }4488 }
4247 // Update the AST node of the decl; even if its contents are unchanged, it may
4248 // have been re-ordered.
4249 decl.src_node = decl_node;
4250 decl.src_line = line;
42514489
4252 decl.is_pub = declaration.flags.is_pub;
4253 decl.is_exported = declaration.flags.is_export;
4254 decl.kind = kind;
4255 decl.zir_decl_index = decl_inst.toOptional();
4256 if (decl.getOwnedFunction(zcu) != null) {4490 if (decl.getOwnedFunction(zcu) != null) {
4491 // TODO this logic is insufficient; namespaces we don't re-scan may still require
4492 // updated line numbers. Look into this!
4257 // TODO Look into detecting when this would be unnecessary by storing enough state4493 // TODO Look into detecting when this would be unnecessary by storing enough state
4258 // in `Decl` to notice that the line number did not change.4494 // in `Decl` to notice that the line number did not change.
4259 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });4495 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
...@@ -4397,6 +4633,11 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato...@@ -4397,6 +4633,11 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
4397 };4633 };
4398 defer sema.deinit();4634 defer sema.deinit();
43994635
4636 // Every runtime function has a dependency on the source of the Decl it originates from.
4637 // It also depends on the value of its owner Decl.
4638 try sema.declareDependency(.{ .src_hash = decl.zir_decl_index.unwrap().? });
4639 try sema.declareDependency(.{ .decl_val = decl_index });
4640
4400 if (func.analysis(ip).inferred_error_set) {4641 if (func.analysis(ip).inferred_error_set) {
4401 const ies = try arena.create(Sema.InferredErrorSet);4642 const ies = try arena.create(Sema.InferredErrorSet);
4402 ies.* = .{ .func = func_index };4643 ies.* = .{ .func = func_index };
src/Sema.zig+80-35
...@@ -2705,6 +2705,37 @@ fn getCaptures(sema: *Sema, block: *Block, extra_index: usize, captures_len: u32...@@ -2705,6 +2705,37 @@ fn getCaptures(sema: *Sema, block: *Block, extra_index: usize, captures_len: u32
2705 return captures;2705 return captures;
2706}2706}
27072707
2708/// Given an `InternPool.WipNamespaceType` or `InternPool.WipEnumType`, apply
2709/// `sema.builtin_type_target_index` to it if necessary.
2710fn wrapWipTy(sema: *Sema, wip_ty: anytype) @TypeOf(wip_ty) {
2711 if (sema.builtin_type_target_index == .none) return wip_ty;
2712 var new = wip_ty;
2713 new.index = sema.builtin_type_target_index;
2714 sema.mod.intern_pool.resolveBuiltinType(new.index, wip_ty.index);
2715 return new;
2716}
2717
2718/// Given a type just looked up in the `InternPool`, check whether it is
2719/// considered outdated on this update. If so, remove it from the pool
2720/// and return `true`.
2721fn maybeRemoveOutdatedType(sema: *Sema, ty: InternPool.Index) !bool {
2722 const zcu = sema.mod;
2723
2724 if (!zcu.comp.debug_incremental) return false;
2725
2726 const decl_index = Type.fromInterned(ty).getOwnerDecl(zcu);
2727 const decl_as_depender = InternPool.Depender.wrap(.{ .decl = decl_index });
2728 const was_outdated = zcu.outdated.swapRemove(decl_as_depender) or
2729 zcu.potentially_outdated.swapRemove(decl_as_depender);
2730 if (!was_outdated) return false;
2731 _ = zcu.outdated_ready.swapRemove(decl_as_depender);
2732 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
2733 zcu.intern_pool.remove(ty);
2734 zcu.declPtr(decl_index).analysis = .dependency_failure;
2735 try zcu.markDependeeOutdated(.{ .decl_val = decl_index });
2736 return true;
2737}
2738
2708fn zirStructDecl(2739fn zirStructDecl(
2709 sema: *Sema,2740 sema: *Sema,
2710 block: *Block,2741 block: *Block,
...@@ -2748,7 +2779,7 @@ fn zirStructDecl(...@@ -2748,7 +2779,7 @@ fn zirStructDecl(
2748 }2779 }
2749 }2780 }
27502781
2751 const wip_ty = switch (try ip.getStructType(gpa, .{2782 const struct_init: InternPool.StructTypeInit = .{
2752 .layout = small.layout,2783 .layout = small.layout,
2753 .fields_len = fields_len,2784 .fields_len = fields_len,
2754 .known_non_opv = small.known_non_opv,2785 .known_non_opv = small.known_non_opv,
...@@ -2763,16 +2794,14 @@ fn zirStructDecl(...@@ -2763,16 +2794,14 @@ fn zirStructDecl(
2763 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),2794 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
2764 .captures = captures,2795 .captures = captures,
2765 } },2796 } },
2766 })) {
2767 .existing => |ty| return Air.internedToRef(ty),
2768 .wip => |wip| wip: {
2769 if (sema.builtin_type_target_index == .none) break :wip wip;
2770 var new = wip;
2771 new.index = sema.builtin_type_target_index;
2772 ip.resolveBuiltinType(new.index, wip.index);
2773 break :wip new;
2774 },
2775 };2797 };
2798 const wip_ty = sema.wrapWipTy(switch (try ip.getStructType(gpa, struct_init)) {
2799 .existing => |ty| wip: {
2800 if (!try sema.maybeRemoveOutdatedType(ty)) return Air.internedToRef(ty);
2801 break :wip (try ip.getStructType(gpa, struct_init)).wip;
2802 },
2803 .wip => |wip| wip,
2804 });
2776 errdefer wip_ty.cancel(ip);2805 errdefer wip_ty.cancel(ip);
27772806
2778 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{2807 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
...@@ -2969,7 +2998,7 @@ fn zirEnumDecl(...@@ -2969,7 +2998,7 @@ fn zirEnumDecl(
2969 if (bag != 0) break true;2998 if (bag != 0) break true;
2970 } else false;2999 } else false;
29713000
2972 const wip_ty = switch (try ip.getEnumType(gpa, .{3001 const enum_init: InternPool.EnumTypeInit = .{
2973 .has_namespace = true or decls_len > 0, // TODO: see below3002 .has_namespace = true or decls_len > 0, // TODO: see below
2974 .has_values = any_values,3003 .has_values = any_values,
2975 .tag_mode = if (small.nonexhaustive)3004 .tag_mode = if (small.nonexhaustive)
...@@ -2983,16 +3012,14 @@ fn zirEnumDecl(...@@ -2983,16 +3012,14 @@ fn zirEnumDecl(
2983 .zir_index = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst),3012 .zir_index = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst),
2984 .captures = captures,3013 .captures = captures,
2985 } },3014 } },
2986 })) {
2987 .wip => |wip| wip: {
2988 if (sema.builtin_type_target_index == .none) break :wip wip;
2989 var new = wip;
2990 new.index = sema.builtin_type_target_index;
2991 ip.resolveBuiltinType(new.index, wip.index);
2992 break :wip new;
2993 },
2994 .existing => |ty| return Air.internedToRef(ty),
2995 };3015 };
3016 const wip_ty = sema.wrapWipTy(switch (try ip.getEnumType(gpa, enum_init)) {
3017 .existing => |ty| wip: {
3018 if (!try sema.maybeRemoveOutdatedType(ty)) return Air.internedToRef(ty);
3019 break :wip (try ip.getEnumType(gpa, enum_init)).wip;
3020 },
3021 .wip => |wip| wip,
3022 });
29963023
2997 // Once this is `true`, we will not delete the decl or type even upon failure, since we3024 // Once this is `true`, we will not delete the decl or type even upon failure, since we
2998 // have finished constructing the type and are in the process of analyzing it.3025 // have finished constructing the type and are in the process of analyzing it.
...@@ -3230,7 +3257,7 @@ fn zirUnionDecl(...@@ -3230,7 +3257,7 @@ fn zirUnionDecl(
3230 const captures = try sema.getCaptures(block, extra_index, captures_len);3257 const captures = try sema.getCaptures(block, extra_index, captures_len);
3231 extra_index += captures_len;3258 extra_index += captures_len;
32323259
3233 const wip_ty = switch (try ip.getUnionType(gpa, .{3260 const union_init: InternPool.UnionTypeInit = .{
3234 .flags = .{3261 .flags = .{
3235 .layout = small.layout,3262 .layout = small.layout,
3236 .status = .none,3263 .status = .none,
...@@ -3257,16 +3284,14 @@ fn zirUnionDecl(...@@ -3257,16 +3284,14 @@ fn zirUnionDecl(
3257 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),3284 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
3258 .captures = captures,3285 .captures = captures,
3259 } },3286 } },
3260 })) {
3261 .wip => |wip| wip: {
3262 if (sema.builtin_type_target_index == .none) break :wip wip;
3263 var new = wip;
3264 new.index = sema.builtin_type_target_index;
3265 ip.resolveBuiltinType(new.index, wip.index);
3266 break :wip new;
3267 },
3268 .existing => |ty| return Air.internedToRef(ty),
3269 };3287 };
3288 const wip_ty = sema.wrapWipTy(switch (try ip.getUnionType(gpa, union_init)) {
3289 .existing => |ty| wip: {
3290 if (!try sema.maybeRemoveOutdatedType(ty)) return Air.internedToRef(ty);
3291 break :wip (try ip.getUnionType(gpa, union_init)).wip;
3292 },
3293 .wip => |wip| wip,
3294 });
3270 errdefer wip_ty.cancel(ip);3295 errdefer wip_ty.cancel(ip);
32713296
3272 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{3297 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
...@@ -3336,15 +3361,20 @@ fn zirOpaqueDecl(...@@ -3336,15 +3361,20 @@ fn zirOpaqueDecl(
3336 const captures = try sema.getCaptures(block, extra_index, captures_len);3361 const captures = try sema.getCaptures(block, extra_index, captures_len);
3337 extra_index += captures_len;3362 extra_index += captures_len;
33383363
3339 const wip_ty = switch (try ip.getOpaqueType(gpa, .{3364 const opaque_init: InternPool.OpaqueTypeInit = .{
3340 .has_namespace = decls_len != 0,3365 .has_namespace = decls_len != 0,
3341 .key = .{ .declared = .{3366 .key = .{ .declared = .{
3342 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),3367 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
3343 .captures = captures,3368 .captures = captures,
3344 } },3369 } },
3345 })) {3370 };
3371 // No `wrapWipTy` needed as no std.builtin types are opaque.
3372 const wip_ty = switch (try ip.getOpaqueType(gpa, opaque_init)) {
3373 .existing => |ty| wip: {
3374 if (!try sema.maybeRemoveOutdatedType(ty)) return Air.internedToRef(ty);
3375 break :wip (try ip.getOpaqueType(gpa, opaque_init)).wip;
3376 },
3346 .wip => |wip| wip,3377 .wip => |wip| wip,
3347 .existing => |ty| return Air.internedToRef(ty),
3348 };3378 };
3349 errdefer wip_ty.cancel(ip);3379 errdefer wip_ty.cancel(ip);
33503380
...@@ -5883,7 +5913,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -5883,7 +5913,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
5883 mod.astGenFile(result.file) catch |err|5913 mod.astGenFile(result.file) catch |err|
5884 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});5914 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
58855915
5886 try mod.semaFile(result.file);5916 try mod.ensureFileAnalyzed(result.file);
5887 const file_root_decl_index = result.file.root_decl.unwrap().?;5917 const file_root_decl_index = result.file.root_decl.unwrap().?;
5888 return sema.analyzeDeclVal(parent_block, src, file_root_decl_index);5918 return sema.analyzeDeclVal(parent_block, src, file_root_decl_index);
5889}5919}
...@@ -13705,7 +13735,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -13705,7 +13735,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
13705 return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });13735 return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
13706 },13736 },
13707 };13737 };
13708 try mod.semaFile(result.file);13738 try mod.ensureFileAnalyzed(result.file);
13709 const file_root_decl_index = result.file.root_decl.unwrap().?;13739 const file_root_decl_index = result.file.root_decl.unwrap().?;
13710 return sema.analyzeDeclVal(block, operand_src, file_root_decl_index);13740 return sema.analyzeDeclVal(block, operand_src, file_root_decl_index);
13711}13741}
...@@ -36432,8 +36462,14 @@ fn resolveInferredErrorSet(...@@ -36432,8 +36462,14 @@ fn resolveInferredErrorSet(
36432 const ip = &mod.intern_pool;36462 const ip = &mod.intern_pool;
36433 const func_index = ip.iesFuncIndex(ies_index);36463 const func_index = ip.iesFuncIndex(ies_index);
36434 const func = mod.funcInfo(func_index);36464 const func = mod.funcInfo(func_index);
36465
36466 try sema.declareDependency(.{ .func_ies = func_index });
36467
36468 // TODO: during an incremental update this might not be `.none`, but the
36469 // function might be out-of-date!
36435 const resolved_ty = func.resolvedErrorSet(ip).*;36470 const resolved_ty = func.resolvedErrorSet(ip).*;
36436 if (resolved_ty != .none) return resolved_ty;36471 if (resolved_ty != .none) return resolved_ty;
36472
36437 if (func.analysis(ip).state == .in_progress)36473 if (func.analysis(ip).state == .in_progress)
36438 return sema.fail(block, src, "unable to resolve inferred error set", .{});36474 return sema.fail(block, src, "unable to resolve inferred error set", .{});
3643936475
...@@ -39052,6 +39088,15 @@ fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type {...@@ -39052,6 +39088,15 @@ fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type {
3905239088
39053pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {39089pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
39054 if (!sema.mod.comp.debug_incremental) return;39090 if (!sema.mod.comp.debug_incremental) return;
39091
39092 // Avoid creating dependencies on ourselves. This situation can arise when we analyze the fields
39093 // of a type and they use `@This()`. This dependency would be unnecessary, and in fact would
39094 // just result in over-analysis since `Zcu.findOutdatedToAnalyze` would never be able to resolve
39095 // the loop.
39096 if (sema.owner_func_index == .none and dependee == .decl_val and dependee.decl_val == sema.owner_decl_index) {
39097 return;
39098 }
39099
39055 const depender = InternPool.Depender.wrap(39100 const depender = InternPool.Depender.wrap(
39056 if (sema.owner_func_index != .none)39101 if (sema.owner_func_index != .none)
39057 .{ .func = sema.owner_func_index }39102 .{ .func = sema.owner_func_index }
test/cases/compile_errors/comptime_decl_name_conflict_resolved.zig created+8
...@@ -0,0 +1,8 @@
1comptime {
2 @compileError("should be reached");
3}
4const comptime_0 = {};
5
6// error
7//
8// :2:5: error: should be reached
test/cases/compile_errors/invalid_duplicate_test_decl_name.zig+2-2
...@@ -6,5 +6,5 @@ test "thingy" {}...@@ -6,5 +6,5 @@ test "thingy" {}
6// target=native6// target=native
7// is_test=true7// is_test=true
8//8//
9// :1:6: error: duplicate test name: test.thingy9// :2:1: error: duplicate test name 'thingy'
10// :2:6: note: other test here10// :1:1: note: other test here