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.
1349613496 const node_tags = tree.nodes.items(.tag);
1349713497 const main_tokens = tree.nodes.items(.main_token);
1349813498 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
1349913508 var decl_count: u32 = 0;
1350013509 for (members) |member_node| {
1350113510 const name_token = switch (node_tags[member_node]) {
......@@ -13525,11 +13534,50 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.
1352513534 break :blk ident;
1352613535 },
1352713536
13528 .@"comptime", .@"usingnamespace", .test_decl => {
13537 .@"comptime", .@"usingnamespace" => {
1352913538 decl_count += 1;
1353013539 continue;
1353113540 },
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
1353313581 else => continue,
1353413582 };
1353513583
src/InternPool.zig+10-3
......@@ -67,6 +67,9 @@ src_hash_deps: std.AutoArrayHashMapUnmanaged(TrackedInst.Index, DepEntry.Index)
6767/// Dependencies on the value of a Decl.
6868/// Value is index into `dep_entries` of the first dependency on this Decl value.
6969decl_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) = .{},
7073/// Dependencies on the full set of names in a ZIR namespace.
7174/// Key refers to a `struct_decl`, `union_decl`, etc.
7275/// Value is index into `dep_entries` of the first dependency on this namespace.
......@@ -167,6 +170,7 @@ pub const Depender = enum(u32) {
167170pub const Dependee = union(enum) {
168171 src_hash: TrackedInst.Index,
169172 decl_val: DeclIndex,
173 func_ies: Index,
170174 namespace: TrackedInst.Index,
171175 namespace_name: NamespaceNameKey,
172176};
......@@ -212,6 +216,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI
212216 const first_entry = switch (dependee) {
213217 .src_hash => |x| ip.src_hash_deps.get(x),
214218 .decl_val => |x| ip.decl_val_deps.get(x),
219 .func_ies => |x| ip.func_ies_deps.get(x),
215220 .namespace => |x| ip.namespace_deps.get(x),
216221 .namespace_name => |x| ip.namespace_name_deps.get(x),
217222 } orelse return .{
......@@ -251,6 +256,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: Depender, depend
251256 const gop = try switch (tag) {
252257 .src_hash => ip.src_hash_deps,
253258 .decl_val => ip.decl_val_deps,
259 .func_ies => ip.func_ies_deps,
254260 .namespace => ip.namespace_deps,
255261 .namespace_name => ip.namespace_name_deps,
256262 }.getOrPut(gpa, dependee_payload);
......@@ -4324,6 +4330,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
43244330
43254331 ip.src_hash_deps.deinit(gpa);
43264332 ip.decl_val_deps.deinit(gpa);
4333 ip.func_ies_deps.deinit(gpa);
43274334 ip.namespace_deps.deinit(gpa);
43284335 ip.namespace_name_deps.deinit(gpa);
43294336
......@@ -7103,7 +7110,7 @@ pub fn getGeneratedTagEnumType(ip: *InternPool, gpa: Allocator, ini: GeneratedTa
71037110 return @enumFromInt(gop.index);
71047111}
71057112
7106pub const OpaqueTypeIni = struct {
7113pub const OpaqueTypeInit = struct {
71077114 has_namespace: bool,
71087115 key: union(enum) {
71097116 declared: struct {
......@@ -7117,7 +7124,7 @@ pub const OpaqueTypeIni = struct {
71177124 },
71187125};
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 {
71217128 const adapter: KeyAdapter = .{ .intern_pool = ip };
71227129 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .opaque_type = switch (ini.key) {
71237130 .declared => |d| .{ .declared = .{
......@@ -9216,7 +9223,7 @@ pub fn funcTypeParamsLen(ip: *const InternPool, i: Index) u32 {
92169223 return ip.extra.items[start + std.meta.fieldIndex(Tag.TypeFunction, "params_len").?];
92179224}
92189225
9219fn unwrapCoercedFunc(ip: *const InternPool, i: Index) Index {
9226pub fn unwrapCoercedFunc(ip: *const InternPool, i: Index) Index {
92209227 const tags = ip.items.items(.tag);
92219228 return switch (tags[@intFromEnum(i)]) {
92229229 .func_coerced => {
src/Module.zig+378-137
......@@ -362,7 +362,7 @@ pub const Decl = struct {
362362 src_line: u32,
363363 /// Index of the ZIR `declaration` instruction from which this `Decl` was created.
364364 /// 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
367367 /// Represents the "shallow" analysis status. For example, for decls that are functions,
368368 /// the function type is analyzed with this set to `in_progress`, however, the semantic
......@@ -428,16 +428,9 @@ pub const Decl = struct {
428428 const Index = InternPool.DeclIndex;
429429 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
438431 pub fn zirBodies(decl: Decl, zcu: *Zcu) Zir.Inst.Declaration.Bodies {
439432 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);
441434 const pl_node = zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
442435 const extra = zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
443436 return extra.data.getBodies(@intCast(extra.end), zir);
......@@ -769,14 +762,14 @@ pub const Namespace = struct {
769762 zcu: *Zcu,
770763
771764 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);
773766 return std.hash.uint32(@intFromEnum(decl.name));
774767 }
775768
776769 pub fn eql(ctx: @This(), a_decl_index: Decl.Index, b_decl_index: Decl.Index, b_index: usize) bool {
777770 _ = b_index;
778 const a_decl = ctx.module.declPtr(a_decl_index);
779 const b_decl = ctx.module.declPtr(b_decl_index);
771 const a_decl = ctx.zcu.declPtr(a_decl_index);
772 const b_decl = ctx.zcu.declPtr(b_decl_index);
780773 return a_decl.name == b_decl.name;
781774 }
782775 };
......@@ -2662,16 +2655,15 @@ pub fn markDependeeOutdated(zcu: *Zcu, dependee: InternPool.Dependee) !void {
26622655 if (opt_po_entry) |e| e.value else 0,
26632656 );
26642657 log.debug("outdated: {}", .{depender});
2665 if (opt_po_entry != null) {
2658 if (opt_po_entry == null) {
26662659 // This is a new entry with no PO dependencies.
26672660 try zcu.outdated_ready.put(zcu.gpa, depender, {});
26682661 }
26692662 // If this is a Decl and was not previously PO, we must recursively
26702663 // mark dependencies on its tyval as PO.
2671 if (opt_po_entry == null) switch (depender.unwrap()) {
2672 .decl => |decl_index| try zcu.markDeclDependenciesPotentiallyOutdated(decl_index),
2673 .func => {},
2674 };
2664 if (opt_po_entry == null) {
2665 try zcu.markTransitiveDependersPotentiallyOutdated(depender);
2666 }
26752667 }
26762668}
26772669
......@@ -2701,15 +2693,19 @@ fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
27012693 // as no longer PO.
27022694 switch (depender.unwrap()) {
27032695 .decl => |decl_index| try zcu.markPoDependeeUpToDate(.{ .decl_val = decl_index }),
2704 .func => {},
2696 .func => |func_index| try zcu.markPoDependeeUpToDate(.{ .func_ies = func_index }),
27052697 }
27062698 }
27072699}
27082700
2709/// Given a Decl which is newly outdated or PO, mark all dependers which depend
2710/// on its tyval as PO.
2711fn markDeclDependenciesPotentiallyOutdated(zcu: *Zcu, decl_index: Decl.Index) !void {
2712 var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index });
2701/// Given a Depender which is newly outdated or PO, mark all Dependers which may
2702/// in turn be PO, due to a dependency on the original Depender's tyval or IES.
2703fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: InternPool.Depender) !void {
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
27132709 while (it.next()) |po| {
27142710 if (zcu.outdated.getPtr(po)) |po_dep_count| {
27152711 // 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
27262722 continue;
27272723 }
27282724 try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1);
2729 // If this ia a Decl, we must recursively mark dependencies
2730 // on its tyval as PO.
2731 switch (po.unwrap()) {
2732 .decl => |po_decl| try zcu.markDeclDependenciesPotentiallyOutdated(po_decl),
2733 .func => {},
2734 }
2725 // This Depender was not already PO, so we must recursively mark its dependers as also PO.
2726 try zcu.markTransitiveDependersPotentiallyOutdated(po);
27352727 }
2736 // TODO: repeat the above for `decl_ty` dependencies when they are introduced
27372728}
27382729
27392730pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.Depender {
......@@ -2859,10 +2850,7 @@ pub fn flushRetryableFailures(zcu: *Zcu) !void {
28592850 // This Depender was not marked PO, but is now outdated. Mark it as
28602851 // such, then recursively mark transitive dependencies as PO.
28612852 try zcu.outdated.put(gpa, depender, 0);
2862 switch (depender.unwrap()) {
2863 .decl => |decl| try zcu.markDeclDependenciesPotentiallyOutdated(decl),
2864 .func => {},
2865 }
2853 try zcu.markTransitiveDependersPotentiallyOutdated(depender);
28662854 }
28672855 zcu.retryable_failures.clearRetainingCapacity();
28682856}
......@@ -2994,6 +2982,15 @@ pub fn mapOldZirToNew(
29942982 }
29952983}
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
29972994/// This ensures that the Decl will have an up-to-date Type and Value populated.
29982995/// However the resolution status of the Type may not be fully resolved.
29992996/// 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 {
30043001
30053002 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
30073009 // Determine whether or not this Decl is outdated, i.e. requires re-analysis
30083010 // even if `complete`. If a Decl is PO, we pessismistically assume that it
30093011 // *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 {
30153017 // dependencies are all up-to-date.
30163018
30173019 const decl_as_depender = InternPool.Depender.wrap(.{ .decl = decl_index });
3018 const was_outdated = mod.outdated.swapRemove(decl_as_depender) or
3020 const decl_was_outdated = mod.outdated.swapRemove(decl_as_depender) or
30193021 mod.potentially_outdated.swapRemove(decl_as_depender);
30203022
3021 if (was_outdated) {
3023 if (decl_was_outdated) {
30223024 _ = mod.outdated_ready.swapRemove(decl_as_depender);
30233025 }
30243026
3027 const was_outdated = mod.outdated_file_root.swapRemove(decl_index) or decl_was_outdated;
3028
30253029 switch (decl.analysis) {
30263030 .in_progress => unreachable,
30273031
......@@ -3057,6 +3061,14 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
30573061 };
30583062 }
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
30603072 break :blk mod.semaDecl(decl_index) catch |err| switch (err) {
30613073 error.AnalysisFail => {
30623074 if (decl.analysis == .in_progress) {
......@@ -3085,13 +3097,15 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
30853097 };
30863098
30873099 // TODO: we do not yet have separate dependencies for decl values vs types.
3088 if (was_outdated) {
3100 if (decl_was_outdated) {
30893101 if (sema_result.invalidate_decl_val or sema_result.invalidate_decl_ref) {
3102 log.debug("Decl tv invalidated ('{d}')", .{@intFromEnum(decl_index)});
30903103 // This dependency was marked as PO, meaning dependees were waiting
30913104 // on its analysis result, and it has turned out to be outdated.
30923105 // Update dependees accordingly.
30933106 try mod.markDependeeOutdated(.{ .decl_val = decl_index });
30943107 } else {
3108 log.debug("Decl tv up-to-date ('{d}')", .{@intFromEnum(decl_index)});
30953109 // This dependency was previously PO, but turned out to be up-to-date.
30963110 // We do not need to queue successive analysis.
30973111 try mod.markPoDependeeUpToDate(.{ .decl_val = decl_index });
......@@ -3099,15 +3113,48 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
30993113 }
31003114}
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 {
31033117 const tracy = trace(@src());
31043118 defer tracy.end();
31053119
3120 const gpa = zcu.gpa;
31063121 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);
31083128 const decl_index = func.owner_decl;
31093129 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
31113158 switch (decl.analysis) {
31123159 .unreferenced => unreachable,
31133160 .in_progress => unreachable,
......@@ -3131,7 +3178,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError
31313178 }
31323179
31333180 switch (func.analysis(ip).state) {
3134 .success,
3181 .success => if (!was_outdated) return,
31353182 .sema_failure,
31363183 .dependency_failure,
31373184 .codegen_failure,
......@@ -3141,7 +3188,10 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError
31413188 .inline_only => unreachable, // don't queue work for this
31423189 }
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
31463196 var tmp_arena = std.heap.ArenaAllocator.init(gpa);
31473197 defer tmp_arena.deinit();
......@@ -3161,6 +3211,20 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError
31613211 };
31623212 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
31643228 const comp = zcu.comp;
31653229
31663230 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)
32993363/// https://github.com/ziglang/zig/issues/14307
33003364pub fn semaPkg(mod: *Module, pkg: *Package.Module) !void {
33013365 const file = (try mod.importPkg(pkg)).file;
3302 return mod.semaFile(file);
3366 if (file.root_decl == .none) {
3367 return mod.semaFile(file);
3368 }
33033369}
33043370
33053371fn 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
33663432 return wip_ty.finish(ip, decl_index, namespace_index.toOptional());
33673433}
33683434
3369/// Regardless of the file status, will create a `Decl` so that we
3370/// can track dependencies and re-analyze when the file becomes outdated.
3371pub fn semaFile(mod: *Module, file: *File) SemaError!void {
3435/// Re-analyze the root Decl of a file on an incremental update.
3436/// If `type_outdated`, the struct type itself is considered outdated and is
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 {
33723500 const tracy = trace(@src());
33733501 defer tracy.end();
33743502
3375 if (file.root_decl != .none) return;
3503 assert(file.root_decl == .none);
33763504
33773505 const gpa = mod.gpa;
33783506 log.debug("semaFile mod={s} sub_file_path={s}", .{
......@@ -3439,9 +3567,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
34393567 },
34403568 .incremental => {},
34413569 }
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.
34453570}
34463571
34473572const SemaDeclResult = packed struct {
......@@ -3462,16 +3587,16 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
34623587 return error.AnalysisFail;
34633588 }
34643589
3465 if (mod.declIsRoot(decl_index)) {
3466 // This comes from an `analyze_decl` job on an incremental update where
3467 // this file changed.
3468 @panic("TODO: update root Decl of modified file");
3469 } else if (decl.owns_tv) {
3470 // We are re-analyzing an owner Decl (for a function or a namespace type).
3471 @panic("TODO: update owner Decl");
3590 assert(!mod.declIsRoot(decl_index));
3591
3592 if (decl.zir_decl_index == .none and decl.owns_tv) {
3593 // We are re-analyzing an anonymous owner Decl (for a function or a namespace type).
3594 return mod.semaAnonOwnerDecl(decl_index);
34723595 }
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
34763601 const gpa = mod.gpa;
34773602 const zir = decl.getFileScope(mod).zir;
......@@ -3763,6 +3888,42 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
37633888 return result;
37643889}
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
37663927pub const ImportFileResult = struct {
37673928 file: *File,
37683929 is_new: bool,
......@@ -4083,26 +4244,87 @@ pub fn scanNamespace(
40834244 const gpa = zcu.gpa;
40844245 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
40864262 try zcu.comp.work_queue.ensureUnusedCapacity(decls.len);
4263
4264 namespace.decls.clearRetainingCapacity();
40874265 try namespace.decls.ensureTotalCapacity(gpa, decls.len);
40884266
4267 namespace.usingnamespace_set.clearRetainingCapacity();
4268
40894269 var scan_decl_iter: ScanDeclIter = .{
40904270 .zcu = zcu,
40914271 .namespace_index = namespace_index,
40924272 .parent_decl = parent_decl,
4273 .seen_decls = &seen_decls,
4274 .existing_by_inst = &existing_by_inst,
4275 .pass = .named,
40934276 };
40944277 for (decls) |decl_inst| {
40954278 try scanDecl(&scan_decl_iter, decl_inst);
40964279 }
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 }
40974299}
40984300
40994301const ScanDeclIter = struct {
41004302 zcu: *Zcu,
41014303 namespace_index: Namespace.Index,
41024304 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 },
41034310 usingnamespace_index: usize = 0,
41044311 comptime_index: usize = 0,
41054312 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 }
41064328};
41074329
41084330fn 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
41264348 // Every Decl needs a name.
41274349 const decl_name: InternPool.NullTerminatedString, const kind: Decl.Kind, const is_named_test: bool = switch (declaration.name) {
41284350 .@"comptime" => info: {
4351 if (iter.pass != .unnamed) return;
41294352 const i = iter.comptime_index;
41304353 iter.comptime_index += 1;
41314354 break :info .{
4132 try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i}),
4355 try iter.avoidNameConflict("comptime_{d}", .{i}),
41334356 .@"comptime",
41344357 false,
41354358 };
41364359 },
41374360 .@"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;
41384365 const i = iter.usingnamespace_index;
41394366 iter.usingnamespace_index += 1;
41404367 break :info .{
4141 try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i}),
4368 try iter.avoidNameConflict("usingnamespace_{d}", .{i}),
41424369 .@"usingnamespace",
41434370 false,
41444371 };
41454372 },
41464373 .unnamed_test => info: {
4374 if (iter.pass != .unnamed) return;
41474375 const i = iter.unnamed_test_index;
41484376 iter.unnamed_test_index += 1;
41494377 break :info .{
4150 try ip.getOrPutStringFmt(gpa, "test_{d}", .{i}),
4378 try iter.avoidNameConflict("test_{d}", .{i}),
41514379 .@"test",
41524380 false,
41534381 };
41544382 },
41554383 .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;
41564386 assert(declaration.flags.has_doc_comment);
41574387 const name = zir.nullTerminatedString(@enumFromInt(zir.extra[extra.end]));
41584388 break :info .{
4159 try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{name}),
4389 try iter.avoidNameConflict("decltest.{s}", .{name}),
41604390 .@"test",
41614391 true,
41624392 };
41634393 },
4164 _ => if (declaration.name.isNamedTest(zir)) .{
4165 try ip.getOrPutStringFmt(gpa, "test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}),
4166 .@"test",
4167 true,
4168 } else .{
4169 try ip.getOrPutString(gpa, zir.nullTerminatedString(declaration.name.toString(zir).?)),
4170 .named,
4171 false,
4394 _ => if (declaration.name.isNamedTest(zir)) info: {
4395 // We consider these to be unnamed since the decl name can be adjusted to avoid conflicts if necessary.
4396 if (iter.pass != .unnamed) return;
4397 break :info .{
4398 try iter.avoidNameConflict("test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}),
4399 .@"test",
4400 true,
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 };
41724411 },
41734412 };
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
41774422 // We create a Decl for it regardless of analysis status.
4178 const gop = try namespace.decls.getOrPutContextAdapted(
4179 gpa,
4180 decl_name,
4181 DeclAdapter{ .zcu = zcu },
4182 Namespace.DeclContext{ .zcu = zcu },
4183 );
4184 const comp = zcu.comp;
4185 if (!gop.found_existing) {
4423
4424 const prev_exported, const decl_index = if (iter.existing_by_inst.get(tracked_inst)) |decl_index| decl_index: {
4425 // We need only update this existing Decl.
4426 const decl = zcu.declPtr(decl_index);
4427 const was_exported = decl.is_exported;
4428 assert(decl.kind == kind); // ZIR tracking should preserve this
4429 assert(decl.alive);
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.
41864438 const new_decl_index = try zcu.allocateNewDecl(namespace_index, decl_node);
41874439 const new_decl = zcu.declPtr(new_decl_index);
41884440 new_decl.kind = kind;
41894441 new_decl.name = decl_name;
4190 if (kind == .@"usingnamespace") {
4191 namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, declaration.flags.is_pub);
4192 }
41934442 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 }
42214443 new_decl.is_pub = declaration.flags.is_pub;
42224444 new_decl.is_exported = declaration.flags.is_export;
4223 new_decl.zir_decl_index = decl_inst.toOptional();
4224 new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive.
4225 return;
4226 }
4227 const decl_index = gop.key_ptr.*;
4445 new_decl.zir_decl_index = tracked_inst.toOptional();
4446 new_decl.alive = true; // This Decl corresponds to an AST node and is therefore always alive.
4447 break :decl_index .{ false, new_decl_index };
4448 };
4449
42284450 const decl = zcu.declPtr(decl_index);
4229 if (kind == .@"test") {
4230 const src_loc = SrcLoc{
4231 .file_scope = decl.getFileScope(zcu),
4232 .parent_decl_node = decl.src_node,
4233 .lazy = .{ .token_offset = 1 },
4234 };
4235 const msg = try ErrorMsg.create(gpa, src_loc, "duplicate test name: {}", .{
4236 decl_name.fmt(ip),
4237 });
4238 errdefer msg.destroy(gpa);
4239 try zcu.failed_decls.putNoClobber(gpa, decl_index, msg);
4240 const other_src_loc = SrcLoc{
4241 .file_scope = namespace.file_scope,
4242 .parent_decl_node = decl_node,
4243 .lazy = .{ .token_offset = 1 },
4244 };
4245 try zcu.errNoteNonLazy(other_src_loc, msg, "other test here", .{});
4451
4452 namespace.decls.putAssumeCapacityNoClobberContext(decl_index, {}, .{ .zcu = zcu });
4453
4454 const comp = zcu.comp;
4455 const decl_mod = namespace.file_scope.mod;
4456 const want_analysis = declaration.flags.is_export or switch (kind) {
4457 .anon => unreachable,
4458 .@"comptime" => true,
4459 .@"usingnamespace" => a: {
4460 namespace.usingnamespace_set.putAssumeCapacityNoClobber(decl_index, declaration.flags.is_pub);
4461 break :a true;
4462 },
4463 .named => false,
4464 .@"test" => a: {
4465 if (!comp.config.is_test) break :a false;
4466 if (decl_mod != zcu.main_mod) break :a false;
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 }
42464488 }
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();
42564490 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!
42574493 // TODO Look into detecting when this would be unnecessary by storing enough state
42584494 // in `Decl` to notice that the line number did not change.
42594495 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
......@@ -4397,6 +4633,11 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
43974633 };
43984634 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
44004641 if (func.analysis(ip).inferred_error_set) {
44014642 const ies = try arena.create(Sema.InferredErrorSet);
44024643 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
27052705 return captures;
27062706}
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
27082739fn zirStructDecl(
27092740 sema: *Sema,
27102741 block: *Block,
......@@ -2748,7 +2779,7 @@ fn zirStructDecl(
27482779 }
27492780 }
27502781
2751 const wip_ty = switch (try ip.getStructType(gpa, .{
2782 const struct_init: InternPool.StructTypeInit = .{
27522783 .layout = small.layout,
27532784 .fields_len = fields_len,
27542785 .known_non_opv = small.known_non_opv,
......@@ -2763,16 +2794,14 @@ fn zirStructDecl(
27632794 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
27642795 .captures = captures,
27652796 } },
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 },
27752797 };
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 });
27762805 errdefer wip_ty.cancel(ip);
27772806
27782807 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
......@@ -2969,7 +2998,7 @@ fn zirEnumDecl(
29692998 if (bag != 0) break true;
29702999 } else false;
29713000
2972 const wip_ty = switch (try ip.getEnumType(gpa, .{
3001 const enum_init: InternPool.EnumTypeInit = .{
29733002 .has_namespace = true or decls_len > 0, // TODO: see below
29743003 .has_values = any_values,
29753004 .tag_mode = if (small.nonexhaustive)
......@@ -2983,16 +3012,14 @@ fn zirEnumDecl(
29833012 .zir_index = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst),
29843013 .captures = captures,
29853014 } },
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),
29953015 };
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
29973024 // Once this is `true`, we will not delete the decl or type even upon failure, since we
29983025 // have finished constructing the type and are in the process of analyzing it.
......@@ -3230,7 +3257,7 @@ fn zirUnionDecl(
32303257 const captures = try sema.getCaptures(block, extra_index, captures_len);
32313258 extra_index += captures_len;
32323259
3233 const wip_ty = switch (try ip.getUnionType(gpa, .{
3260 const union_init: InternPool.UnionTypeInit = .{
32343261 .flags = .{
32353262 .layout = small.layout,
32363263 .status = .none,
......@@ -3257,16 +3284,14 @@ fn zirUnionDecl(
32573284 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
32583285 .captures = captures,
32593286 } },
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),
32693287 };
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 });
32703295 errdefer wip_ty.cancel(ip);
32713296
32723297 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
......@@ -3336,15 +3361,20 @@ fn zirOpaqueDecl(
33363361 const captures = try sema.getCaptures(block, extra_index, captures_len);
33373362 extra_index += captures_len;
33383363
3339 const wip_ty = switch (try ip.getOpaqueType(gpa, .{
3364 const opaque_init: InternPool.OpaqueTypeInit = .{
33403365 .has_namespace = decls_len != 0,
33413366 .key = .{ .declared = .{
33423367 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
33433368 .captures = captures,
33443369 } },
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 },
33463377 .wip => |wip| wip,
3347 .existing => |ty| return Air.internedToRef(ty),
33483378 };
33493379 errdefer wip_ty.cancel(ip);
33503380
......@@ -5883,7 +5913,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
58835913 mod.astGenFile(result.file) catch |err|
58845914 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);
58875917 const file_root_decl_index = result.file.root_decl.unwrap().?;
58885918 return sema.analyzeDeclVal(parent_block, src, file_root_decl_index);
58895919}
......@@ -13705,7 +13735,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1370513735 return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
1370613736 },
1370713737 };
13708 try mod.semaFile(result.file);
13738 try mod.ensureFileAnalyzed(result.file);
1370913739 const file_root_decl_index = result.file.root_decl.unwrap().?;
1371013740 return sema.analyzeDeclVal(block, operand_src, file_root_decl_index);
1371113741}
......@@ -36432,8 +36462,14 @@ fn resolveInferredErrorSet(
3643236462 const ip = &mod.intern_pool;
3643336463 const func_index = ip.iesFuncIndex(ies_index);
3643436464 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!
3643536470 const resolved_ty = func.resolvedErrorSet(ip).*;
3643636471 if (resolved_ty != .none) return resolved_ty;
36472
3643736473 if (func.analysis(ip).state == .in_progress)
3643836474 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 {
3905239088
3905339089pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
3905439090 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
3905539100 const depender = InternPool.Depender.wrap(
3905639101 if (sema.owner_func_index != .none)
3905739102 .{ .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" {}
66// target=native
77// is_test=true
88//
9// :1:6: error: duplicate test name: test.thingy
10// :2:6: note: other test here
9// :2:1: error: duplicate test name 'thingy'
10// :1:1: note: other test here