authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-02-02 03:19:23+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-02-04 18:38:39+00:00
log7f4bd247c7735ccf277c9bba42222e014cacf856
treeb47acb0631fc101995b03dd415efe587cec9738b
parenta1b607acb5c1e9dd03760efd7078185e7628b29d
signaturelock-open Commit is signed but in an unrecognized format.

compiler: re-introduce dependencies for incremental compilation

Sema now tracks dependencies appropriately. Early logic in Zcu for resolving outdated decls/functions is in place. The setup used does not support `usingnamespace`; compilations using this construct are not yet supported by this incremental compilation model.

5 files changed, 537 insertions(+), 57 deletions(-)

src/Compilation.zig+29-1
...@@ -2807,6 +2807,13 @@ const Header = extern struct {...@@ -2807,6 +2807,13 @@ const Header = extern struct {
2807 limbs_len: u32,2807 limbs_len: u32,
2808 string_bytes_len: u32,2808 string_bytes_len: u32,
2809 tracked_insts_len: u32,2809 tracked_insts_len: u32,
2810 src_hash_deps_len: u32,
2811 decl_val_deps_len: u32,
2812 namespace_deps_len: u32,
2813 namespace_name_deps_len: u32,
2814 first_dependency_len: u32,
2815 dep_entries_len: u32,
2816 free_dep_entries_len: u32,
2810 },2817 },
2811};2818};
28122819
...@@ -2814,7 +2821,7 @@ const Header = extern struct {...@@ -2814,7 +2821,7 @@ const Header = extern struct {
2814/// saved, such as the target and most CLI flags. A cache hit will only occur2821/// saved, such as the target and most CLI flags. A cache hit will only occur
2815/// when subsequent compiler invocations use the same set of flags.2822/// when subsequent compiler invocations use the same set of flags.
2816pub fn saveState(comp: *Compilation) !void {2823pub fn saveState(comp: *Compilation) !void {
2817 var bufs_list: [7]std.os.iovec_const = undefined;2824 var bufs_list: [19]std.os.iovec_const = undefined;
2818 var bufs_len: usize = 0;2825 var bufs_len: usize = 0;
28192826
2820 const lf = comp.bin_file orelse return;2827 const lf = comp.bin_file orelse return;
...@@ -2828,6 +2835,13 @@ pub fn saveState(comp: *Compilation) !void {...@@ -2828,6 +2835,13 @@ pub fn saveState(comp: *Compilation) !void {
2828 .limbs_len = @intCast(ip.limbs.items.len),2835 .limbs_len = @intCast(ip.limbs.items.len),
2829 .string_bytes_len = @intCast(ip.string_bytes.items.len),2836 .string_bytes_len = @intCast(ip.string_bytes.items.len),
2830 .tracked_insts_len = @intCast(ip.tracked_insts.count()),2837 .tracked_insts_len = @intCast(ip.tracked_insts.count()),
2838 .src_hash_deps_len = @intCast(ip.src_hash_deps.count()),
2839 .decl_val_deps_len = @intCast(ip.decl_val_deps.count()),
2840 .namespace_deps_len = @intCast(ip.namespace_deps.count()),
2841 .namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()),
2842 .first_dependency_len = @intCast(ip.first_dependency.count()),
2843 .dep_entries_len = @intCast(ip.dep_entries.items.len),
2844 .free_dep_entries_len = @intCast(ip.free_dep_entries.items.len),
2831 },2845 },
2832 };2846 };
2833 addBuf(&bufs_list, &bufs_len, mem.asBytes(&header));2847 addBuf(&bufs_list, &bufs_len, mem.asBytes(&header));
...@@ -2838,6 +2852,20 @@ pub fn saveState(comp: *Compilation) !void {...@@ -2838,6 +2852,20 @@ pub fn saveState(comp: *Compilation) !void {
2838 addBuf(&bufs_list, &bufs_len, ip.string_bytes.items);2852 addBuf(&bufs_list, &bufs_len, ip.string_bytes.items);
2839 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.tracked_insts.keys()));2853 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.tracked_insts.keys()));
28402854
2855 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.src_hash_deps.keys()));
2856 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.src_hash_deps.values()));
2857 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.decl_val_deps.keys()));
2858 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.decl_val_deps.values()));
2859 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.namespace_deps.keys()));
2860 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.namespace_deps.values()));
2861 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.namespace_name_deps.keys()));
2862 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.namespace_name_deps.values()));
2863
2864 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.first_dependency.keys()));
2865 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.first_dependency.values()));
2866 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.dep_entries.items));
2867 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.free_dep_entries.items));
2868
2841 // TODO: compilation errors2869 // TODO: compilation errors
2842 // TODO: files2870 // TODO: files
2843 // TODO: namespaces2871 // TODO: namespaces
src/InternPool.zig+278-11
...@@ -58,6 +58,38 @@ string_table: std.HashMapUnmanaged(...@@ -58,6 +58,38 @@ string_table: std.HashMapUnmanaged(
58/// persists across incremental updates.58/// persists across incremental updates.
59tracked_insts: std.AutoArrayHashMapUnmanaged(TrackedInst, void) = .{},59tracked_insts: std.AutoArrayHashMapUnmanaged(TrackedInst, void) = .{},
6060
61/// Dependencies on the source code hash associated with a ZIR instruction.
62/// * For a `declaration`, this is the entire declaration body.
63/// * For a `struct_decl`, `union_decl`, etc, this is the source of the fields (but not declarations).
64/// * For a `func`, this is the source of the full function signature.
65/// These are also invalidated if tracking fails for this instruction.
66/// Value is index into `dep_entries` of the first dependency on this hash.
67src_hash_deps: std.AutoArrayHashMapUnmanaged(TrackedInst.Index, DepEntry.Index) = .{},
68/// Dependencies on the value of a Decl.
69/// Value is index into `dep_entries` of the first dependency on this Decl value.
70decl_val_deps: std.AutoArrayHashMapUnmanaged(DeclIndex, DepEntry.Index) = .{},
71/// Dependencies on the full set of names in a ZIR namespace.
72/// Key refers to a `struct_decl`, `union_decl`, etc.
73/// Value is index into `dep_entries` of the first dependency on this namespace.
74namespace_deps: std.AutoArrayHashMapUnmanaged(TrackedInst.Index, DepEntry.Index) = .{},
75/// Dependencies on the (non-)existence of some name in a namespace.
76/// Value is index into `dep_entries` of the first dependency on this name.
77namespace_name_deps: std.AutoArrayHashMapUnmanaged(NamespaceNameKey, DepEntry.Index) = .{},
78
79/// Given a `Depender`, points to an entry in `dep_entries` whose `depender`
80/// matches. The `next_dependee` field can be used to iterate all such entries
81/// and remove them from the corresponding lists.
82first_dependency: std.AutoArrayHashMapUnmanaged(Depender, DepEntry.Index) = .{},
83
84/// Stores dependency information. The hashmaps declared above are used to look
85/// up entries in this list as required. This is not stored in `extra` so that
86/// we can use `free_dep_entries` to track free indices, since dependencies are
87/// removed frequently.
88dep_entries: std.ArrayListUnmanaged(DepEntry) = .{},
89/// Stores unused indices in `dep_entries` which can be reused without a full
90/// garbage collection pass.
91free_dep_entries: std.ArrayListUnmanaged(DepEntry.Index) = .{},
92
61pub const TrackedInst = extern struct {93pub const TrackedInst = extern struct {
62 path_digest: Cache.BinDigest,94 path_digest: Cache.BinDigest,
63 inst: Zir.Inst.Index,95 inst: Zir.Inst.Index,
...@@ -70,6 +102,19 @@ pub const TrackedInst = extern struct {...@@ -70,6 +102,19 @@ pub const TrackedInst = extern struct {
70 pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Zir.Inst.Index {102 pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Zir.Inst.Index {
71 return ip.tracked_insts.keys()[@intFromEnum(i)].inst;103 return ip.tracked_insts.keys()[@intFromEnum(i)].inst;
72 }104 }
105 pub fn toOptional(i: TrackedInst.Index) Optional {
106 return @enumFromInt(@intFromEnum(i));
107 }
108 pub const Optional = enum(u32) {
109 none = std.math.maxInt(u32),
110 _,
111 pub fn unwrap(opt: Optional) ?TrackedInst.Index {
112 return switch (opt) {
113 .none => null,
114 _ => @enumFromInt(@intFromEnum(opt)),
115 };
116 }
117 };
73 };118 };
74};119};
75120
...@@ -82,6 +127,202 @@ pub fn trackZir(ip: *InternPool, gpa: Allocator, file: *Module.File, inst: Zir.I...@@ -82,6 +127,202 @@ pub fn trackZir(ip: *InternPool, gpa: Allocator, file: *Module.File, inst: Zir.I
82 return @enumFromInt(gop.index);127 return @enumFromInt(gop.index);
83}128}
84129
130/// Reperesents the "source" of a dependency edge, i.e. either a Decl or a
131/// runtime function (represented as an InternPool index).
132/// MSB is 0 for a Decl, 1 for a function.
133pub const Depender = enum(u32) {
134 _,
135 pub const Unwrapped = union(enum) {
136 decl: DeclIndex,
137 func: InternPool.Index,
138 };
139 pub fn unwrap(dep: Depender) Unwrapped {
140 const tag: u1 = @truncate(@intFromEnum(dep) >> 31);
141 const val: u31 = @truncate(@intFromEnum(dep));
142 return switch (tag) {
143 0 => .{ .decl = @enumFromInt(val) },
144 1 => .{ .func = @enumFromInt(val) },
145 };
146 }
147 pub fn wrap(raw: Unwrapped) Depender {
148 return @enumFromInt(switch (raw) {
149 .decl => |decl| @intFromEnum(decl),
150 .func => |func| (1 << 31) | @intFromEnum(func),
151 });
152 }
153 pub fn toOptional(dep: Depender) Optional {
154 return @enumFromInt(@intFromEnum(dep));
155 }
156 pub const Optional = enum(u32) {
157 none = std.math.maxInt(u32),
158 _,
159 pub fn unwrap(opt: Optional) ?Depender {
160 return switch (opt) {
161 .none => null,
162 _ => @enumFromInt(@intFromEnum(opt)),
163 };
164 }
165 };
166};
167
168pub const Dependee = union(enum) {
169 src_hash: TrackedInst.Index,
170 decl_val: DeclIndex,
171 namespace: TrackedInst.Index,
172 namespace_name: NamespaceNameKey,
173};
174
175pub fn removeDependenciesForDepender(ip: *InternPool, gpa: Allocator, depender: Depender) void {
176 var opt_idx = (ip.first_dependency.fetchSwapRemove(depender) orelse return).value.toOptional();
177
178 while (opt_idx.unwrap()) |idx| {
179 const dep = ip.dep_entries.items[@intFromEnum(idx)];
180 opt_idx = dep.next_dependee;
181
182 const prev_idx = dep.prev.unwrap() orelse {
183 // This entry is the start of a list in some `*_deps`.
184 // We cannot easily remove this mapping, so this must remain as a dummy entry.
185 ip.dep_entries.items[@intFromEnum(idx)].depender = .none;
186 continue;
187 };
188
189 ip.dep_entries.items[@intFromEnum(prev_idx)].next = dep.next;
190 if (dep.next.unwrap()) |next_idx| {
191 ip.dep_entries.items[@intFromEnum(next_idx)].prev = dep.prev;
192 }
193
194 ip.free_dep_entries.append(gpa, idx) catch {
195 // This memory will be reclaimed on the next garbage collection.
196 // Thus, we do not need to propagate this error.
197 };
198 }
199}
200
201pub const DependencyIterator = struct {
202 ip: *const InternPool,
203 next_entry: DepEntry.Index.Optional,
204 pub fn next(it: *DependencyIterator) ?Depender {
205 const idx = it.next_entry.unwrap() orelse return null;
206 const entry = it.ip.dep_entries.items[@intFromEnum(idx)];
207 it.next_entry = entry.next;
208 return entry.depender.unwrap().?;
209 }
210};
211
212pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyIterator {
213 const first_entry = switch (dependee) {
214 .src_hash => |x| ip.src_hash_deps.get(x),
215 .decl_val => |x| ip.decl_val_deps.get(x),
216 .namespace => |x| ip.namespace_deps.get(x),
217 .namespace_name => |x| ip.namespace_name_deps.get(x),
218 } orelse return .{
219 .ip = ip,
220 .next_entry = .none,
221 };
222 if (ip.dep_entries.items[@intFromEnum(first_entry)].depender == .none) return .{
223 .ip = ip,
224 .next_entry = .none,
225 };
226 return .{
227 .ip = ip,
228 .next_entry = first_entry.toOptional(),
229 };
230}
231
232pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: Depender, dependee: Dependee) Allocator.Error!void {
233 const first_depender_dep: DepEntry.Index.Optional = if (ip.first_dependency.get(depender)) |idx| dep: {
234 // The entry already exists, so there is capacity to overwrite it later.
235 break :dep idx.toOptional();
236 } else none: {
237 // Ensure there is capacity available to add this dependency later.
238 try ip.first_dependency.ensureUnusedCapacity(gpa, 1);
239 break :none .none;
240 };
241
242 // We're very likely to need space for a new entry - reserve it now to avoid
243 // the need for error cleanup logic.
244 if (ip.free_dep_entries.items.len == 0) {
245 try ip.dep_entries.ensureUnusedCapacity(gpa, 1);
246 }
247
248 // This block should allocate an entry and prepend it to the relevant `*_deps` list.
249 // The `next` field should be correctly initialized; all other fields may be undefined.
250 const new_index: DepEntry.Index = switch (dependee) {
251 inline else => |dependee_payload, tag| new_index: {
252 const gop = try switch (tag) {
253 .src_hash => ip.src_hash_deps,
254 .decl_val => ip.decl_val_deps,
255 .namespace => ip.namespace_deps,
256 .namespace_name => ip.namespace_name_deps,
257 }.getOrPut(gpa, dependee_payload);
258
259 if (gop.found_existing and ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].depender == .none) {
260 // Dummy entry, so we can reuse it rather than allocating a new one!
261 ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].next = .none;
262 break :new_index gop.value_ptr.*;
263 }
264
265 // Prepend a new dependency.
266 const new_index: DepEntry.Index, const ptr = if (ip.free_dep_entries.popOrNull()) |new_index| new: {
267 break :new .{ new_index, &ip.dep_entries.items[@intFromEnum(new_index)] };
268 } else .{ @enumFromInt(ip.dep_entries.items.len), ip.dep_entries.addOneAssumeCapacity() };
269 ptr.next = if (gop.found_existing) gop.value_ptr.*.toOptional() else .none;
270 gop.value_ptr.* = new_index;
271 break :new_index new_index;
272 },
273 };
274
275 ip.dep_entries.items[@intFromEnum(new_index)].depender = depender.toOptional();
276 ip.dep_entries.items[@intFromEnum(new_index)].prev = .none;
277 ip.dep_entries.items[@intFromEnum(new_index)].next_dependee = first_depender_dep;
278 ip.first_dependency.putAssumeCapacity(depender, new_index);
279}
280
281/// String is the name whose existence the dependency is on.
282/// DepEntry.Index refers to the first such dependency.
283pub const NamespaceNameKey = struct {
284 /// The instruction (`struct_decl` etc) which owns the namespace in question.
285 namespace: TrackedInst.Index,
286 /// The name whose existence the dependency is on.
287 name: NullTerminatedString,
288};
289
290pub const DepEntry = extern struct {
291 /// If null, this is a dummy entry - all other fields are `undefined`. It is
292 /// the first and only entry in one of `intern_pool.*_deps`, and does not
293 /// appear in any list by `first_dependency`, but is not in
294 /// `free_dep_entries` since `*_deps` stores a reference to it.
295 depender: Depender.Optional,
296 /// Index into `dep_entries` forming a doubly linked list of all dependencies on this dependee.
297 /// Used to iterate all dependers for a given dependee during an update.
298 /// null if this is the end of the list.
299 next: DepEntry.Index.Optional,
300 /// The other link for `next`.
301 /// null if this is the start of the list.
302 prev: DepEntry.Index.Optional,
303 /// Index into `dep_entries` forming a singly linked list of dependencies *of* `depender`.
304 /// Used to efficiently remove all `DepEntry`s for a single `depender` when it is re-analyzed.
305 /// null if this is the end of the list.
306 next_dependee: DepEntry.Index.Optional,
307
308 pub const Index = enum(u32) {
309 _,
310 pub fn toOptional(dep: DepEntry.Index) Optional {
311 return @enumFromInt(@intFromEnum(dep));
312 }
313 pub const Optional = enum(u32) {
314 none = std.math.maxInt(u32),
315 _,
316 pub fn unwrap(opt: Optional) ?DepEntry.Index {
317 return switch (opt) {
318 .none => null,
319 _ => @enumFromInt(@intFromEnum(opt)),
320 };
321 }
322 };
323 };
324};
325
85const FieldMap = std.ArrayHashMapUnmanaged(void, void, std.array_hash_map.AutoContext(void), false);326const FieldMap = std.ArrayHashMapUnmanaged(void, void, std.array_hash_map.AutoContext(void), false);
86327
87const builtin = @import("builtin");328const builtin = @import("builtin");
...@@ -428,6 +669,7 @@ pub const Key = union(enum) {...@@ -428,6 +669,7 @@ pub const Key = union(enum) {
428 decl: DeclIndex,669 decl: DeclIndex,
429 /// Represents the declarations inside this opaque.670 /// Represents the declarations inside this opaque.
430 namespace: NamespaceIndex,671 namespace: NamespaceIndex,
672 zir_index: TrackedInst.Index.Optional,
431 };673 };
432674
433 /// Although packed structs and non-packed structs are encoded differently,675 /// Although packed structs and non-packed structs are encoded differently,
...@@ -440,7 +682,7 @@ pub const Key = union(enum) {...@@ -440,7 +682,7 @@ pub const Key = union(enum) {
440 /// `none` when the struct has no declarations.682 /// `none` when the struct has no declarations.
441 namespace: OptionalNamespaceIndex,683 namespace: OptionalNamespaceIndex,
442 /// Index of the struct_decl ZIR instruction.684 /// Index of the struct_decl ZIR instruction.
443 zir_index: TrackedInst.Index,685 zir_index: TrackedInst.Index.Optional,
444 layout: std.builtin.Type.ContainerLayout,686 layout: std.builtin.Type.ContainerLayout,
445 field_names: NullTerminatedString.Slice,687 field_names: NullTerminatedString.Slice,
446 field_types: Index.Slice,688 field_types: Index.Slice,
...@@ -684,7 +926,7 @@ pub const Key = union(enum) {...@@ -684,7 +926,7 @@ pub const Key = union(enum) {
684 }926 }
685927
686 /// Asserts the struct is not packed.928 /// Asserts the struct is not packed.
687 pub fn setZirIndex(s: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index) void {929 pub fn setZirIndex(s: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void {
688 assert(s.layout != .Packed);930 assert(s.layout != .Packed);
689 const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?;931 const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?;
690 ip.extra.items[s.extra_index + field_index] = @intFromEnum(new_zir_index);932 ip.extra.items[s.extra_index + field_index] = @intFromEnum(new_zir_index);
...@@ -800,7 +1042,7 @@ pub const Key = union(enum) {...@@ -800,7 +1042,7 @@ pub const Key = union(enum) {
800 flags: Tag.TypeUnion.Flags,1042 flags: Tag.TypeUnion.Flags,
801 /// The enum that provides the list of field names and values.1043 /// The enum that provides the list of field names and values.
802 enum_tag_ty: Index,1044 enum_tag_ty: Index,
803 zir_index: TrackedInst.Index,1045 zir_index: TrackedInst.Index.Optional,
8041046
805 /// The returned pointer expires with any addition to the `InternPool`.1047 /// The returned pointer expires with any addition to the `InternPool`.
806 pub fn flagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeUnion.Flags {1048 pub fn flagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeUnion.Flags {
...@@ -889,6 +1131,7 @@ pub const Key = union(enum) {...@@ -889,6 +1131,7 @@ pub const Key = union(enum) {
889 /// This is ignored by `get` but will be provided by `indexToKey` when1131 /// This is ignored by `get` but will be provided by `indexToKey` when
890 /// a value map exists.1132 /// a value map exists.
891 values_map: OptionalMapIndex = .none,1133 values_map: OptionalMapIndex = .none,
1134 zir_index: TrackedInst.Index.Optional,
8921135
893 pub const TagMode = enum {1136 pub const TagMode = enum {
894 /// The integer tag type was auto-numbered by zig.1137 /// The integer tag type was auto-numbered by zig.
...@@ -953,6 +1196,7 @@ pub const Key = union(enum) {...@@ -953,6 +1196,7 @@ pub const Key = union(enum) {
953 tag_mode: EnumType.TagMode,1196 tag_mode: EnumType.TagMode,
954 /// This may be updated via `setTagType` later.1197 /// This may be updated via `setTagType` later.
955 tag_ty: Index = .none,1198 tag_ty: Index = .none,
1199 zir_index: TrackedInst.Index.Optional,
9561200
957 pub fn toEnumType(self: @This()) EnumType {1201 pub fn toEnumType(self: @This()) EnumType {
958 return .{1202 return .{
...@@ -962,6 +1206,7 @@ pub const Key = union(enum) {...@@ -962,6 +1206,7 @@ pub const Key = union(enum) {
962 .tag_mode = self.tag_mode,1206 .tag_mode = self.tag_mode,
963 .names = .{ .start = 0, .len = 0 },1207 .names = .{ .start = 0, .len = 0 },
964 .values = .{ .start = 0, .len = 0 },1208 .values = .{ .start = 0, .len = 0 },
1209 .zir_index = self.zir_index,
965 };1210 };
966 }1211 }
9671212
...@@ -1909,7 +2154,7 @@ pub const UnionType = struct {...@@ -1909,7 +2154,7 @@ pub const UnionType = struct {
1909 /// If this slice has length 0 it means all elements are `none`.2154 /// If this slice has length 0 it means all elements are `none`.
1910 field_aligns: Alignment.Slice,2155 field_aligns: Alignment.Slice,
1911 /// Index of the union_decl ZIR instruction.2156 /// Index of the union_decl ZIR instruction.
1912 zir_index: TrackedInst.Index,2157 zir_index: TrackedInst.Index.Optional,
1913 /// Index into extra array of the `flags` field.2158 /// Index into extra array of the `flags` field.
1914 flags_index: u32,2159 flags_index: u32,
1915 /// Copied from `enum_tag_ty`.2160 /// Copied from `enum_tag_ty`.
...@@ -2003,10 +2248,10 @@ pub const UnionType = struct {...@@ -2003,10 +2248,10 @@ pub const UnionType = struct {
2003 }2248 }
20042249
2005 /// This does not mutate the field of UnionType.2250 /// This does not mutate the field of UnionType.
2006 pub fn setZirIndex(self: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index) void {2251 pub fn setZirIndex(self: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void {
2007 const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;2252 const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;
2008 const zir_index_field_index = std.meta.fieldIndex(Tag.TypeUnion, "zir_index").?;2253 const zir_index_field_index = std.meta.fieldIndex(Tag.TypeUnion, "zir_index").?;
2009 const ptr: *TrackedInst.Index =2254 const ptr: *TrackedInst.Index.Optional =
2010 @ptrCast(&ip.extra.items[self.flags_index - flags_field_index + zir_index_field_index]);2255 @ptrCast(&ip.extra.items[self.flags_index - flags_field_index + zir_index_field_index]);
2011 ptr.* = new_zir_index;2256 ptr.* = new_zir_index;
2012 }2257 }
...@@ -3099,7 +3344,7 @@ pub const Tag = enum(u8) {...@@ -3099,7 +3344,7 @@ pub const Tag = enum(u8) {
3099 namespace: NamespaceIndex,3344 namespace: NamespaceIndex,
3100 /// The enum that provides the list of field names and values.3345 /// The enum that provides the list of field names and values.
3101 tag_ty: Index,3346 tag_ty: Index,
3102 zir_index: TrackedInst.Index,3347 zir_index: TrackedInst.Index.Optional,
31033348
3104 pub const Flags = packed struct(u32) {3349 pub const Flags = packed struct(u32) {
3105 runtime_tag: UnionType.RuntimeTag,3350 runtime_tag: UnionType.RuntimeTag,
...@@ -3121,7 +3366,7 @@ pub const Tag = enum(u8) {...@@ -3121,7 +3366,7 @@ pub const Tag = enum(u8) {
3121 /// 2. init: Index for each fields_len // if tag is type_struct_packed_inits3366 /// 2. init: Index for each fields_len // if tag is type_struct_packed_inits
3122 pub const TypeStructPacked = struct {3367 pub const TypeStructPacked = struct {
3123 decl: DeclIndex,3368 decl: DeclIndex,
3124 zir_index: TrackedInst.Index,3369 zir_index: TrackedInst.Index.Optional,
3125 fields_len: u32,3370 fields_len: u32,
3126 namespace: OptionalNamespaceIndex,3371 namespace: OptionalNamespaceIndex,
3127 backing_int_ty: Index,3372 backing_int_ty: Index,
...@@ -3168,7 +3413,7 @@ pub const Tag = enum(u8) {...@@ -3168,7 +3413,7 @@ pub const Tag = enum(u8) {
3168 /// 7. field_offset: u32 // for each field in declared order, undef until layout_resolved3413 /// 7. field_offset: u32 // for each field in declared order, undef until layout_resolved
3169 pub const TypeStruct = struct {3414 pub const TypeStruct = struct {
3170 decl: DeclIndex,3415 decl: DeclIndex,
3171 zir_index: TrackedInst.Index,3416 zir_index: TrackedInst.Index.Optional,
3172 fields_len: u32,3417 fields_len: u32,
3173 flags: Flags,3418 flags: Flags,
3174 size: u32,3419 size: u32,
...@@ -3523,6 +3768,7 @@ pub const EnumExplicit = struct {...@@ -3523,6 +3768,7 @@ pub const EnumExplicit = struct {
3523 /// If this is `none`, it means the trailing tag values are absent because3768 /// If this is `none`, it means the trailing tag values are absent because
3524 /// they are auto-numbered.3769 /// they are auto-numbered.
3525 values_map: OptionalMapIndex,3770 values_map: OptionalMapIndex,
3771 zir_index: TrackedInst.Index.Optional,
3526};3772};
35273773
3528/// Trailing:3774/// Trailing:
...@@ -3538,6 +3784,7 @@ pub const EnumAuto = struct {...@@ -3538,6 +3784,7 @@ pub const EnumAuto = struct {
3538 fields_len: u32,3784 fields_len: u32,
3539 /// Maps field names to declaration index.3785 /// Maps field names to declaration index.
3540 names_map: MapIndex,3786 names_map: MapIndex,
3787 zir_index: TrackedInst.Index.Optional,
3541};3788};
35423789
3543pub const PackedU64 = packed struct(u64) {3790pub const PackedU64 = packed struct(u64) {
...@@ -3759,6 +4006,16 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {...@@ -3759,6 +4006,16 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
37594006
3760 ip.tracked_insts.deinit(gpa);4007 ip.tracked_insts.deinit(gpa);
37614008
4009 ip.src_hash_deps.deinit(gpa);
4010 ip.decl_val_deps.deinit(gpa);
4011 ip.namespace_deps.deinit(gpa);
4012 ip.namespace_name_deps.deinit(gpa);
4013
4014 ip.first_dependency.deinit(gpa);
4015
4016 ip.dep_entries.deinit(gpa);
4017 ip.free_dep_entries.deinit(gpa);
4018
3762 ip.* = undefined;4019 ip.* = undefined;
3763}4020}
37644021
...@@ -3885,6 +4142,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -3885,6 +4142,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
3885 .tag_mode = .auto,4142 .tag_mode = .auto,
3886 .names_map = enum_auto.data.names_map.toOptional(),4143 .names_map = enum_auto.data.names_map.toOptional(),
3887 .values_map = .none,4144 .values_map = .none,
4145 .zir_index = enum_auto.data.zir_index,
3888 } };4146 } };
3889 },4147 },
3890 .type_enum_explicit => ip.indexToKeyEnum(data, .explicit),4148 .type_enum_explicit => ip.indexToKeyEnum(data, .explicit),
...@@ -4493,6 +4751,7 @@ fn indexToKeyEnum(ip: *const InternPool, data: u32, tag_mode: Key.EnumType.TagMo...@@ -4493,6 +4751,7 @@ fn indexToKeyEnum(ip: *const InternPool, data: u32, tag_mode: Key.EnumType.TagMo
4493 .tag_mode = tag_mode,4751 .tag_mode = tag_mode,
4494 .names_map = enum_explicit.data.names_map.toOptional(),4752 .names_map = enum_explicit.data.names_map.toOptional(),
4495 .values_map = enum_explicit.data.values_map,4753 .values_map = enum_explicit.data.values_map,
4754 .zir_index = enum_explicit.data.zir_index,
4496 } };4755 } };
4497}4756}
44984757
...@@ -5329,7 +5588,7 @@ pub const UnionTypeInit = struct {...@@ -5329,7 +5588,7 @@ pub const UnionTypeInit = struct {
5329 flags: Tag.TypeUnion.Flags,5588 flags: Tag.TypeUnion.Flags,
5330 decl: DeclIndex,5589 decl: DeclIndex,
5331 namespace: NamespaceIndex,5590 namespace: NamespaceIndex,
5332 zir_index: TrackedInst.Index,5591 zir_index: TrackedInst.Index.Optional,
5333 fields_len: u32,5592 fields_len: u32,
5334 enum_tag_ty: Index,5593 enum_tag_ty: Index,
5335 /// May have length 0 which leaves the values unset until later.5594 /// May have length 0 which leaves the values unset until later.
...@@ -5401,7 +5660,7 @@ pub const StructTypeInit = struct {...@@ -5401,7 +5660,7 @@ pub const StructTypeInit = struct {
5401 decl: DeclIndex,5660 decl: DeclIndex,
5402 namespace: OptionalNamespaceIndex,5661 namespace: OptionalNamespaceIndex,
5403 layout: std.builtin.Type.ContainerLayout,5662 layout: std.builtin.Type.ContainerLayout,
5404 zir_index: TrackedInst.Index,5663 zir_index: TrackedInst.Index.Optional,
5405 fields_len: u32,5664 fields_len: u32,
5406 known_non_opv: bool,5665 known_non_opv: bool,
5407 requires_comptime: RequiresComptime,5666 requires_comptime: RequiresComptime,
...@@ -6264,6 +6523,7 @@ fn getIncompleteEnumAuto(...@@ -6264,6 +6523,7 @@ fn getIncompleteEnumAuto(
6264 .int_tag_type = int_tag_type,6523 .int_tag_type = int_tag_type,
6265 .names_map = names_map,6524 .names_map = names_map,
6266 .fields_len = enum_type.fields_len,6525 .fields_len = enum_type.fields_len,
6526 .zir_index = enum_type.zir_index,
6267 });6527 });
62686528
6269 ip.items.appendAssumeCapacity(.{6529 ip.items.appendAssumeCapacity(.{
...@@ -6314,6 +6574,7 @@ fn getIncompleteEnumExplicit(...@@ -6314,6 +6574,7 @@ fn getIncompleteEnumExplicit(
6314 .fields_len = enum_type.fields_len,6574 .fields_len = enum_type.fields_len,
6315 .names_map = names_map,6575 .names_map = names_map,
6316 .values_map = values_map,6576 .values_map = values_map,
6577 .zir_index = enum_type.zir_index,
6317 });6578 });
63186579
6319 ip.items.appendAssumeCapacity(.{6580 ip.items.appendAssumeCapacity(.{
...@@ -6339,6 +6600,7 @@ pub const GetEnumInit = struct {...@@ -6339,6 +6600,7 @@ pub const GetEnumInit = struct {
6339 names: []const NullTerminatedString,6600 names: []const NullTerminatedString,
6340 values: []const Index,6601 values: []const Index,
6341 tag_mode: Key.EnumType.TagMode,6602 tag_mode: Key.EnumType.TagMode,
6603 zir_index: TrackedInst.Index.Optional,
6342};6604};
63436605
6344pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Error!Index {6606pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Error!Index {
...@@ -6355,6 +6617,7 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro...@@ -6355,6 +6617,7 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro
6355 .tag_mode = undefined,6617 .tag_mode = undefined,
6356 .names_map = undefined,6618 .names_map = undefined,
6357 .values_map = undefined,6619 .values_map = undefined,
6620 .zir_index = undefined,
6358 },6621 },
6359 }, adapter);6622 }, adapter);
6360 if (gop.found_existing) return @enumFromInt(gop.index);6623 if (gop.found_existing) return @enumFromInt(gop.index);
...@@ -6380,6 +6643,7 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro...@@ -6380,6 +6643,7 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro
6380 .int_tag_type = ini.tag_ty,6643 .int_tag_type = ini.tag_ty,
6381 .names_map = names_map,6644 .names_map = names_map,
6382 .fields_len = fields_len,6645 .fields_len = fields_len,
6646 .zir_index = ini.zir_index,
6383 }),6647 }),
6384 });6648 });
6385 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));6649 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
...@@ -6416,6 +6680,7 @@ pub fn finishGetEnum(...@@ -6416,6 +6680,7 @@ pub fn finishGetEnum(
6416 .fields_len = fields_len,6680 .fields_len = fields_len,
6417 .names_map = names_map,6681 .names_map = names_map,
6418 .values_map = values_map,6682 .values_map = values_map,
6683 .zir_index = ini.zir_index,
6419 }),6684 }),
6420 });6685 });
6421 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));6686 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
...@@ -6507,6 +6772,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {...@@ -6507,6 +6772,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
6507 OptionalNullTerminatedString,6772 OptionalNullTerminatedString,
6508 Tag.TypePointer.VectorIndex,6773 Tag.TypePointer.VectorIndex,
6509 TrackedInst.Index,6774 TrackedInst.Index,
6775 TrackedInst.Index.Optional,
6510 => @intFromEnum(@field(extra, field.name)),6776 => @intFromEnum(@field(extra, field.name)),
65116777
6512 u32,6778 u32,
...@@ -6583,6 +6849,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct...@@ -6583,6 +6849,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct
6583 OptionalNullTerminatedString,6849 OptionalNullTerminatedString,
6584 Tag.TypePointer.VectorIndex,6850 Tag.TypePointer.VectorIndex,
6585 TrackedInst.Index,6851 TrackedInst.Index,
6852 TrackedInst.Index.Optional,
6586 => @enumFromInt(int32),6853 => @enumFromInt(int32),
65876854
6588 u32,6855 u32,
src/Module.zig+140-37
...@@ -149,6 +149,10 @@ error_limit: ErrorInt,...@@ -149,6 +149,10 @@ error_limit: ErrorInt,
149/// previous analysis.149/// previous analysis.
150generation: u32 = 0,150generation: u32 = 0,
151151
152/// Value is the number of PO dependencies of this Depender.
153potentially_outdated: std.AutoArrayHashMapUnmanaged(InternPool.Depender, u32) = .{},
154outdated: std.AutoArrayHashMapUnmanaged(InternPool.Depender, void) = .{},
155
152stage1_flags: packed struct {156stage1_flags: packed struct {
153 have_winmain: bool = false,157 have_winmain: bool = false,
154 have_wwinmain: bool = false,158 have_wwinmain: bool = false,
...@@ -680,14 +684,6 @@ pub const Decl = struct {...@@ -680,14 +684,6 @@ pub const Decl = struct {
680 return mod.namespacePtr(decl.src_namespace).file_scope;684 return mod.namespacePtr(decl.src_namespace).file_scope;
681 }685 }
682686
683 pub fn removeDependant(decl: *Decl, other: Decl.Index) void {
684 assert(decl.dependants.swapRemove(other));
685 }
686
687 pub fn removeDependency(decl: *Decl, other: Decl.Index) void {
688 assert(decl.dependencies.swapRemove(other));
689 }
690
691 pub fn getExternDecl(decl: Decl, mod: *Module) OptionalIndex {687 pub fn getExternDecl(decl: Decl, mod: *Module) OptionalIndex {
692 assert(decl.has_tv);688 assert(decl.has_tv);
693 return switch (mod.intern_pool.indexToKey(decl.val.toIntern())) {689 return switch (mod.intern_pool.indexToKey(decl.val.toIntern())) {
...@@ -838,14 +834,6 @@ pub const File = struct {...@@ -838,14 +834,6 @@ pub const File = struct {
838 /// undefined until `zir_loaded == true`.834 /// undefined until `zir_loaded == true`.
839 path_digest: Cache.BinDigest = undefined,835 path_digest: Cache.BinDigest = undefined,
840836
841 /// Used by change detection algorithm, after astgen, contains the
842 /// set of decls that existed in the previous ZIR but not in the new one.
843 deleted_decls: ArrayListUnmanaged(Decl.Index) = .{},
844 /// Used by change detection algorithm, after astgen, contains the
845 /// set of decls that existed both in the previous ZIR and in the new one,
846 /// but their source code has been modified.
847 outdated_decls: ArrayListUnmanaged(Decl.Index) = .{},
848
849 /// The most recent successful ZIR for this file, with no errors.837 /// The most recent successful ZIR for this file, with no errors.
850 /// This is only populated when a previously successful ZIR838 /// This is only populated when a previously successful ZIR
851 /// newly introduces compile errors during an update. When ZIR is839 /// newly introduces compile errors during an update. When ZIR is
...@@ -898,8 +886,6 @@ pub const File = struct {...@@ -898,8 +886,6 @@ pub const File = struct {
898 gpa.free(file.sub_file_path);886 gpa.free(file.sub_file_path);
899 file.unload(gpa);887 file.unload(gpa);
900 }888 }
901 file.deleted_decls.deinit(gpa);
902 file.outdated_decls.deinit(gpa);
903 file.references.deinit(gpa);889 file.references.deinit(gpa);
904 if (file.root_decl.unwrap()) |root_decl| {890 if (file.root_decl.unwrap()) |root_decl| {
905 mod.destroyDecl(root_decl);891 mod.destroyDecl(root_decl);
...@@ -2498,6 +2484,8 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2498,6 +2484,8 @@ pub fn deinit(zcu: *Zcu) void {
24982484
2499 zcu.global_error_set.deinit(gpa);2485 zcu.global_error_set.deinit(gpa);
25002486
2487 zcu.potentially_outdated.deinit(gpa);
2488
2501 zcu.test_functions.deinit(gpa);2489 zcu.test_functions.deinit(gpa);
25022490
2503 for (zcu.global_assembly.values()) |s| {2491 for (zcu.global_assembly.values()) |s| {
...@@ -2856,27 +2844,18 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -2856,27 +2844,18 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
2856 }2844 }
28572845
2858 if (file.prev_zir) |prev_zir| {2846 if (file.prev_zir) |prev_zir| {
2859 // Iterate over all Namespace objects contained within this File, looking at the
2860 // previous and new ZIR together and update the references to point
2861 // to the new one. For example, Decl name, Decl zir_decl_index, and Namespace
2862 // decl_table keys need to get updated to point to the new memory, even if the
2863 // underlying source code is unchanged.
2864 // We do not need to hold any locks at this time because all the Decl and Namespace
2865 // objects being touched are specific to this File, and the only other concurrent
2866 // tasks are touching other File objects.
2867 try updateZirRefs(mod, file, prev_zir.*);2847 try updateZirRefs(mod, file, prev_zir.*);
2868 // At this point, `file.outdated_decls` and `file.deleted_decls` are populated,
2869 // and semantic analysis will deal with them properly.
2870 // No need to keep previous ZIR.2848 // No need to keep previous ZIR.
2871 prev_zir.deinit(gpa);2849 prev_zir.deinit(gpa);
2872 gpa.destroy(prev_zir);2850 gpa.destroy(prev_zir);
2873 file.prev_zir = null;2851 file.prev_zir = null;
2874 } else if (file.root_decl.unwrap()) |root_decl| {2852 }
2875 // This is an update, but it is the first time the File has succeeded2853
2876 // ZIR. We must mark it outdated since we have already tried to2854 if (file.root_decl.unwrap()) |root_decl| {
2877 // semantically analyze it.2855 // The root of this file must be re-analyzed, since the file has changed.
2878 try file.outdated_decls.resize(gpa, 1);2856 comp.mutex.lock();
2879 file.outdated_decls.items[0] = root_decl;2857 defer comp.mutex.unlock();
2858 try mod.outdated.put(gpa, InternPool.Depender.wrap(.{ .decl = root_decl }), {});
2880 }2859 }
2881}2860}
28822861
...@@ -2950,25 +2929,142 @@ fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File)...@@ -2950,25 +2929,142 @@ fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File)
2950 return zir;2929 return zir;
2951}2930}
29522931
2932/// This is called from the AstGen thread pool, so must acquire
2933/// the Compilation mutex when acting on shared state.
2953fn updateZirRefs(zcu: *Module, file: *File, old_zir: Zir) !void {2934fn updateZirRefs(zcu: *Module, file: *File, old_zir: Zir) !void {
2954 const gpa = zcu.gpa;2935 const gpa = zcu.gpa;
2936 const new_zir = file.zir;
29552937
2956 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};2938 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};
2957 defer inst_map.deinit(gpa);2939 defer inst_map.deinit(gpa);
29582940
2959 try mapOldZirToNew(gpa, old_zir, file.zir, &inst_map);2941 try mapOldZirToNew(gpa, old_zir, new_zir, &inst_map);
2942
2943 const old_tag = old_zir.instructions.items(.tag);
2944 const old_data = old_zir.instructions.items(.data);
29602945
2961 // TODO: this should be done after all AstGen workers complete, to avoid2946 // TODO: this should be done after all AstGen workers complete, to avoid
2962 // iterating over this full set for every updated file.2947 // iterating over this full set for every updated file.
2963 for (zcu.intern_pool.tracked_insts.keys()) |*ti| {2948 for (zcu.intern_pool.tracked_insts.keys(), 0..) |*ti, idx_raw| {
2949 const ti_idx: InternPool.TrackedInst.Index = @enumFromInt(idx_raw);
2964 if (!std.mem.eql(u8, &ti.path_digest, &file.path_digest)) continue;2950 if (!std.mem.eql(u8, &ti.path_digest, &file.path_digest)) continue;
2951 const old_inst = ti.inst;
2965 ti.inst = inst_map.get(ti.inst) orelse {2952 ti.inst = inst_map.get(ti.inst) orelse {
2966 // TODO: invalidate this `TrackedInst` via the dependency mechanism2953 // Tracking failed for this instruction. Invalidate associated `src_hash` deps.
2954 zcu.comp.mutex.lock();
2955 defer zcu.comp.mutex.unlock();
2956 try zcu.markDependeeOutdated(.{ .src_hash = ti_idx });
2967 continue;2957 continue;
2968 };2958 };
2959
2960 // If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies.
2961 const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) {
2962 .extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) {
2963 .struct_decl, .union_decl, .opaque_decl, .enum_decl => true,
2964 else => false,
2965 },
2966 else => false,
2967 };
2968 if (!has_namespace) continue;
2969
2970 var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
2971 defer old_names.deinit(zcu.gpa);
2972 {
2973 var it = old_zir.declIterator(old_inst);
2974 while (it.next()) |decl_inst| {
2975 const decl_name = old_zir.getDeclaration(decl_inst)[0].name;
2976 switch (decl_name) {
2977 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
2978 _ => if (decl_name.isNamedTest(old_zir)) continue,
2979 }
2980 const name_zir = decl_name.toString(old_zir).?;
2981 const name_ip = try zcu.intern_pool.getOrPutString(
2982 zcu.gpa,
2983 old_zir.nullTerminatedString(name_zir),
2984 );
2985 try old_names.put(zcu.gpa, name_ip, {});
2986 }
2987 }
2988 var any_change = false;
2989 {
2990 var it = new_zir.declIterator(ti.inst);
2991 while (it.next()) |decl_inst| {
2992 const decl_name = old_zir.getDeclaration(decl_inst)[0].name;
2993 switch (decl_name) {
2994 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
2995 _ => if (decl_name.isNamedTest(old_zir)) continue,
2996 }
2997 const name_zir = decl_name.toString(old_zir).?;
2998 const name_ip = try zcu.intern_pool.getOrPutString(
2999 zcu.gpa,
3000 old_zir.nullTerminatedString(name_zir),
3001 );
3002 if (!old_names.swapRemove(name_ip)) continue;
3003 // Name added
3004 any_change = true;
3005 zcu.comp.mutex.lock();
3006 defer zcu.comp.mutex.unlock();
3007 try zcu.markDependeeOutdated(.{ .namespace_name = .{
3008 .namespace = ti_idx,
3009 .name = name_ip,
3010 } });
3011 }
3012 }
3013 // The only elements remaining in `old_names` now are any names which were removed.
3014 for (old_names.keys()) |name_ip| {
3015 any_change = true;
3016 zcu.comp.mutex.lock();
3017 defer zcu.comp.mutex.unlock();
3018 try zcu.markDependeeOutdated(.{ .namespace_name = .{
3019 .namespace = ti_idx,
3020 .name = name_ip,
3021 } });
3022 }
3023
3024 if (any_change) {
3025 zcu.comp.mutex.lock();
3026 defer zcu.comp.mutex.unlock();
3027 try zcu.markDependeeOutdated(.{ .namespace = ti_idx });
3028 }
3029 }
3030}
3031
3032pub fn markDependeeOutdated(zcu: *Zcu, dependee: InternPool.Dependee) !void {
3033 var it = zcu.intern_pool.dependencyIterator(dependee);
3034 while (it.next()) |depender| {
3035 if (zcu.outdated.contains(depender)) continue;
3036 const was_po = zcu.potentially_outdated.swapRemove(depender);
3037 try zcu.outdated.putNoClobber(zcu.gpa, depender, {});
3038 // If this is a Decl and was not previously PO, we must recursively
3039 // mark dependencies on its tyval as PO.
3040 if (was_po) switch (depender.unwrap()) {
3041 .decl => |decl_index| try zcu.markDeclDependenciesPotentiallyOutdated(decl_index),
3042 .func => {},
3043 };
2969 }3044 }
2970}3045}
29713046
3047/// Given a Decl which is newly outdated or PO, mark all dependers which depend
3048/// on its tyval as PO.
3049fn markDeclDependenciesPotentiallyOutdated(zcu: *Zcu, decl_index: Decl.Index) !void {
3050 var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index });
3051 while (it.next()) |po| {
3052 if (zcu.potentially_outdated.getPtr(po)) |n| {
3053 // There is now one more PO dependency.
3054 n.* += 1;
3055 continue;
3056 }
3057 try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1);
3058 // If this ia a Decl, we must recursively mark dependencies
3059 // on its tyval as PO.
3060 switch (po.unwrap()) {
3061 .decl => |po_decl| try zcu.markDeclDependenciesPotentiallyOutdated(po_decl),
3062 .func => {},
3063 }
3064 }
3065 // TODO: repeat the above for `decl_ty` dependencies when they are introduced
3066}
3067
2972pub fn mapOldZirToNew(3068pub fn mapOldZirToNew(
2973 gpa: Allocator,3069 gpa: Allocator,
2974 old_zir: Zir,3070 old_zir: Zir,
...@@ -3535,6 +3631,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3535,6 +3631,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
3535 break :blk .none;3631 break :blk .none;
3536 };3632 };
35373633
3634 mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
3635
3538 decl.analysis = .in_progress;3636 decl.analysis = .in_progress;
35393637
3540 var analysis_arena = std.heap.ArenaAllocator.init(gpa);3638 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
...@@ -3564,6 +3662,9 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3564,6 +3662,9 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
3564 };3662 };
3565 defer sema.deinit();3663 defer sema.deinit();
35663664
3665 // Every Decl has a dependency on its own source.
3666 try sema.declareDependency(.{ .src_hash = try ip.trackZir(sema.gpa, decl.getFileScope(mod), decl.zir_decl_index.unwrap().?) });
3667
3567 assert(!mod.declIsRoot(decl_index));3668 assert(!mod.declIsRoot(decl_index));
35683669
3569 var block_scope: Sema.Block = .{3670 var block_scope: Sema.Block = .{
...@@ -4362,6 +4463,8 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato...@@ -4362,6 +4463,8 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
4362 const decl_index = func.owner_decl;4463 const decl_index = func.owner_decl;
4363 const decl = mod.declPtr(decl_index);4464 const decl = mod.declPtr(decl_index);
43644465
4466 mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index }));
4467
4365 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);4468 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
4366 defer comptime_mutable_decls.deinit();4469 defer comptime_mutable_decls.deinit();
43674470
src/Sema.zig+78-8
...@@ -2748,7 +2748,7 @@ pub fn getStructType(...@@ -2748,7 +2748,7 @@ pub fn getStructType(
2748 const ty = try ip.getStructType(gpa, .{2748 const ty = try ip.getStructType(gpa, .{
2749 .decl = decl,2749 .decl = decl,
2750 .namespace = namespace.toOptional(),2750 .namespace = namespace.toOptional(),
2751 .zir_index = tracked_inst,2751 .zir_index = tracked_inst.toOptional(),
2752 .layout = small.layout,2752 .layout = small.layout,
2753 .known_non_opv = small.known_non_opv,2753 .known_non_opv = small.known_non_opv,
2754 .is_tuple = small.is_tuple,2754 .is_tuple = small.is_tuple,
...@@ -2789,6 +2789,12 @@ fn zirStructDecl(...@@ -2789,6 +2789,12 @@ fn zirStructDecl(
2789 new_decl.owns_tv = true;2789 new_decl.owns_tv = true;
2790 errdefer mod.abortAnonDecl(new_decl_index);2790 errdefer mod.abortAnonDecl(new_decl_index);
27912791
2792 try ip.addDependency(
2793 sema.gpa,
2794 InternPool.Depender.wrap(.{ .decl = new_decl_index }),
2795 .{ .src_hash = try ip.trackZir(sema.gpa, block.getFileScope(mod), inst) },
2796 );
2797
2792 const new_namespace_index = try mod.createNamespace(.{2798 const new_namespace_index = try mod.createNamespace(.{
2793 .parent = block.namespace.toOptional(),2799 .parent = block.namespace.toOptional(),
2794 .ty = undefined,2800 .ty = undefined,
...@@ -2973,6 +2979,12 @@ fn zirEnumDecl(...@@ -2973,6 +2979,12 @@ fn zirEnumDecl(
2973 new_decl.owns_tv = true;2979 new_decl.owns_tv = true;
2974 errdefer if (!done) mod.abortAnonDecl(new_decl_index);2980 errdefer if (!done) mod.abortAnonDecl(new_decl_index);
29752981
2982 try mod.intern_pool.addDependency(
2983 sema.gpa,
2984 InternPool.Depender.wrap(.{ .decl = new_decl_index }),
2985 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
2986 );
2987
2976 const new_namespace_index = try mod.createNamespace(.{2988 const new_namespace_index = try mod.createNamespace(.{
2977 .parent = block.namespace.toOptional(),2989 .parent = block.namespace.toOptional(),
2978 .ty = undefined,2990 .ty = undefined,
...@@ -3008,6 +3020,7 @@ fn zirEnumDecl(...@@ -3008,6 +3020,7 @@ fn zirEnumDecl(
3008 .auto3020 .auto
3009 else3021 else
3010 .explicit,3022 .explicit,
3023 .zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(),
3011 });3024 });
3012 if (sema.builtin_type_target_index != .none) {3025 if (sema.builtin_type_target_index != .none) {
3013 mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, incomplete_enum.index);3026 mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, incomplete_enum.index);
...@@ -3225,6 +3238,12 @@ fn zirUnionDecl(...@@ -3225,6 +3238,12 @@ fn zirUnionDecl(
3225 new_decl.owns_tv = true;3238 new_decl.owns_tv = true;
3226 errdefer mod.abortAnonDecl(new_decl_index);3239 errdefer mod.abortAnonDecl(new_decl_index);
32273240
3241 try mod.intern_pool.addDependency(
3242 sema.gpa,
3243 InternPool.Depender.wrap(.{ .decl = new_decl_index }),
3244 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
3245 );
3246
3228 const new_namespace_index = try mod.createNamespace(.{3247 const new_namespace_index = try mod.createNamespace(.{
3229 .parent = block.namespace.toOptional(),3248 .parent = block.namespace.toOptional(),
3230 .ty = undefined,3249 .ty = undefined,
...@@ -3254,7 +3273,7 @@ fn zirUnionDecl(...@@ -3254,7 +3273,7 @@ fn zirUnionDecl(
3254 },3273 },
3255 .decl = new_decl_index,3274 .decl = new_decl_index,
3256 .namespace = new_namespace_index,3275 .namespace = new_namespace_index,
3257 .zir_index = try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst),3276 .zir_index = (try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst)).toOptional(),
3258 .fields_len = fields_len,3277 .fields_len = fields_len,
3259 .enum_tag_ty = .none,3278 .enum_tag_ty = .none,
3260 .field_types = &.{},3279 .field_types = &.{},
...@@ -3318,6 +3337,12 @@ fn zirOpaqueDecl(...@@ -3318,6 +3337,12 @@ fn zirOpaqueDecl(
3318 new_decl.owns_tv = true;3337 new_decl.owns_tv = true;
3319 errdefer mod.abortAnonDecl(new_decl_index);3338 errdefer mod.abortAnonDecl(new_decl_index);
33203339
3340 try mod.intern_pool.addDependency(
3341 sema.gpa,
3342 InternPool.Depender.wrap(.{ .decl = new_decl_index }),
3343 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
3344 );
3345
3321 const new_namespace_index = try mod.createNamespace(.{3346 const new_namespace_index = try mod.createNamespace(.{
3322 .parent = block.namespace.toOptional(),3347 .parent = block.namespace.toOptional(),
3323 .ty = undefined,3348 .ty = undefined,
...@@ -3329,6 +3354,7 @@ fn zirOpaqueDecl(...@@ -3329,6 +3354,7 @@ fn zirOpaqueDecl(
3329 const opaque_ty = try mod.intern(.{ .opaque_type = .{3354 const opaque_ty = try mod.intern(.{ .opaque_type = .{
3330 .decl = new_decl_index,3355 .decl = new_decl_index,
3331 .namespace = new_namespace_index,3356 .namespace = new_namespace_index,
3357 .zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(),
3332 } });3358 } });
3333 // TODO: figure out InternPool removals for incremental compilation3359 // TODO: figure out InternPool removals for incremental compilation
3334 //errdefer mod.intern_pool.remove(opaque_ty);3360 //errdefer mod.intern_pool.remove(opaque_ty);
...@@ -7890,6 +7916,8 @@ fn instantiateGenericCall(...@@ -7890,6 +7916,8 @@ fn instantiateGenericCall(
7890 const generic_owner_func = mod.intern_pool.indexToKey(generic_owner).func;7916 const generic_owner_func = mod.intern_pool.indexToKey(generic_owner).func;
7891 const generic_owner_ty_info = mod.typeToFunc(Type.fromInterned(generic_owner_func.ty)).?;7917 const generic_owner_ty_info = mod.typeToFunc(Type.fromInterned(generic_owner_func.ty)).?;
78927918
7919 try sema.declareDependency(.{ .src_hash = generic_owner_func.zir_body_inst });
7920
7893 // Even though there may already be a generic instantiation corresponding7921 // Even though there may already be a generic instantiation corresponding
7894 // to this callsite, we must evaluate the expressions of the generic7922 // to this callsite, we must evaluate the expressions of the generic
7895 // function signature with the values of the callsite plugged in.7923 // function signature with the values of the callsite plugged in.
...@@ -13594,6 +13622,12 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -13594,6 +13622,12 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
13594 });13622 });
1359513623
13596 try sema.checkNamespaceType(block, lhs_src, container_type);13624 try sema.checkNamespaceType(block, lhs_src, container_type);
13625 if (container_type.typeDeclInst(mod)) |type_decl_inst| {
13626 try sema.declareDependency(.{ .namespace_name = .{
13627 .namespace = type_decl_inst,
13628 .name = decl_name,
13629 } });
13630 }
1359713631
13598 const namespace = container_type.getNamespaceIndex(mod).unwrap() orelse13632 const namespace = container_type.getNamespaceIndex(mod).unwrap() orelse
13599 return .bool_false;13633 return .bool_false;
...@@ -17447,6 +17481,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17447,6 +17481,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17447 const type_info_ty = try sema.getBuiltinType("Type");17481 const type_info_ty = try sema.getBuiltinType("Type");
17448 const type_info_tag_ty = type_info_ty.unionTagType(mod).?;17482 const type_info_tag_ty = type_info_ty.unionTagType(mod).?;
1744917483
17484 if (ty.typeDeclInst(mod)) |type_decl_inst| {
17485 try sema.declareDependency(.{ .namespace = type_decl_inst });
17486 }
17487
17450 switch (ty.zigTypeTag(mod)) {17488 switch (ty.zigTypeTag(mod)) {
17451 .Type,17489 .Type,
17452 .Void,17490 .Void,
...@@ -21313,6 +21351,7 @@ fn zirReify(...@@ -21313,6 +21351,7 @@ fn zirReify(
21313 else21351 else
21314 .explicit,21352 .explicit,
21315 .tag_ty = int_tag_ty.toIntern(),21353 .tag_ty = int_tag_ty.toIntern(),
21354 .zir_index = .none,
21316 });21355 });
21317 // TODO: figure out InternPool removals for incremental compilation21356 // TODO: figure out InternPool removals for incremental compilation
21318 //errdefer ip.remove(incomplete_enum.index);21357 //errdefer ip.remove(incomplete_enum.index);
...@@ -21410,6 +21449,7 @@ fn zirReify(...@@ -21410,6 +21449,7 @@ fn zirReify(
21410 const opaque_ty = try mod.intern(.{ .opaque_type = .{21449 const opaque_ty = try mod.intern(.{ .opaque_type = .{
21411 .decl = new_decl_index,21450 .decl = new_decl_index,
21412 .namespace = new_namespace_index,21451 .namespace = new_namespace_index,
21452 .zir_index = .none,
21413 } });21453 } });
21414 // TODO: figure out InternPool removals for incremental compilation21454 // TODO: figure out InternPool removals for incremental compilation
21415 //errdefer ip.remove(opaque_ty);21455 //errdefer ip.remove(opaque_ty);
...@@ -21628,7 +21668,7 @@ fn zirReify(...@@ -21628,7 +21668,7 @@ fn zirReify(
21628 .namespace = new_namespace_index,21668 .namespace = new_namespace_index,
21629 .enum_tag_ty = enum_tag_ty,21669 .enum_tag_ty = enum_tag_ty,
21630 .fields_len = fields_len,21670 .fields_len = fields_len,
21631 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst), // TODO: should reified types be handled differently?21671 .zir_index = .none,
21632 .flags = .{21672 .flags = .{
21633 .layout = layout,21673 .layout = layout,
21634 .status = .have_field_types,21674 .status = .have_field_types,
...@@ -21796,7 +21836,7 @@ fn reifyStruct(...@@ -21796,7 +21836,7 @@ fn reifyStruct(
21796 const ty = try ip.getStructType(gpa, .{21836 const ty = try ip.getStructType(gpa, .{
21797 .decl = new_decl_index,21837 .decl = new_decl_index,
21798 .namespace = .none,21838 .namespace = .none,
21799 .zir_index = try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst), // TODO: should reified types be handled differently?21839 .zir_index = .none,
21800 .layout = layout,21840 .layout = layout,
21801 .known_non_opv = false,21841 .known_non_opv = false,
21802 .fields_len = fields_len,21842 .fields_len = fields_len,
...@@ -26416,6 +26456,7 @@ fn prepareSimplePanic(sema: *Sema, block: *Block) !void {...@@ -26416,6 +26456,7 @@ fn prepareSimplePanic(sema: *Sema, block: *Block) !void {
26416 // owns the function.26456 // owns the function.
26417 try sema.ensureDeclAnalyzed(decl_index);26457 try sema.ensureDeclAnalyzed(decl_index);
26418 const tv = try mod.declPtr(decl_index).typedValue();26458 const tv = try mod.declPtr(decl_index).typedValue();
26459 try sema.declareDependency(.{ .decl_val = decl_index });
26419 assert(tv.ty.zigTypeTag(mod) == .Fn);26460 assert(tv.ty.zigTypeTag(mod) == .Fn);
26420 assert(try sema.fnHasRuntimeBits(tv.ty));26461 assert(try sema.fnHasRuntimeBits(tv.ty));
26421 const func_index = tv.val.toIntern();26462 const func_index = tv.val.toIntern();
...@@ -26837,6 +26878,13 @@ fn fieldVal(...@@ -26837,6 +26878,13 @@ fn fieldVal(
26837 const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?;26878 const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?;
26838 const child_type = val.toType();26879 const child_type = val.toType();
2683926880
26881 if (child_type.typeDeclInst(mod)) |type_decl_inst| {
26882 try sema.declareDependency(.{ .namespace_name = .{
26883 .namespace = type_decl_inst,
26884 .name = field_name,
26885 } });
26886 }
26887
26840 switch (try child_type.zigTypeTagOrPoison(mod)) {26888 switch (try child_type.zigTypeTagOrPoison(mod)) {
26841 .ErrorSet => {26889 .ErrorSet => {
26842 switch (ip.indexToKey(child_type.toIntern())) {26890 switch (ip.indexToKey(child_type.toIntern())) {
...@@ -27060,6 +27108,13 @@ fn fieldPtr(...@@ -27060,6 +27108,13 @@ fn fieldPtr(
27060 const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?;27108 const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?;
27061 const child_type = val.toType();27109 const child_type = val.toType();
2706227110
27111 if (child_type.typeDeclInst(mod)) |type_decl_inst| {
27112 try sema.declareDependency(.{ .namespace_name = .{
27113 .namespace = type_decl_inst,
27114 .name = field_name,
27115 } });
27116 }
27117
27063 switch (child_type.zigTypeTag(mod)) {27118 switch (child_type.zigTypeTag(mod)) {
27064 .ErrorSet => {27119 .ErrorSet => {
27065 switch (ip.indexToKey(child_type.toIntern())) {27120 switch (ip.indexToKey(child_type.toIntern())) {
...@@ -31129,6 +31184,7 @@ fn beginComptimePtrLoad(...@@ -31129,6 +31184,7 @@ fn beginComptimePtrLoad(
31129 const is_mutable = ptr.addr == .mut_decl;31184 const is_mutable = ptr.addr == .mut_decl;
31130 const decl = mod.declPtr(decl_index);31185 const decl = mod.declPtr(decl_index);
31131 const decl_tv = try decl.typedValue();31186 const decl_tv = try decl.typedValue();
31187 try sema.declareDependency(.{ .decl_val = decl_index });
31132 if (decl.val.getVariable(mod) != null) return error.RuntimeLoad;31188 if (decl.val.getVariable(mod) != null) return error.RuntimeLoad;
3113331189
31134 const layout_defined = decl.ty.hasWellDefinedLayout(mod);31190 const layout_defined = decl.ty.hasWellDefinedLayout(mod);
...@@ -32382,6 +32438,8 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn...@@ -32382,6 +32438,8 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn
3238232438
32383 const decl = mod.declPtr(decl_index);32439 const decl = mod.declPtr(decl_index);
32384 const decl_tv = try decl.typedValue();32440 const decl_tv = try decl.typedValue();
32441 // TODO: if this is a `decl_ref`, only depend on decl type
32442 try sema.declareDependency(.{ .decl_val = decl_index });
32385 const ptr_ty = try sema.ptrType(.{32443 const ptr_ty = try sema.ptrType(.{
32386 .child = decl_tv.ty.toIntern(),32444 .child = decl_tv.ty.toIntern(),
32387 .flags = .{32445 .flags = .{
...@@ -35678,7 +35736,7 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp...@@ -35678,7 +35736,7 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
35678 break :blk accumulator;35736 break :blk accumulator;
35679 };35737 };
3568035738
35681 const zir_index = struct_type.zir_index.resolve(ip);35739 const zir_index = struct_type.zir_index.unwrap().?.resolve(ip);
35682 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;35740 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
35683 assert(extended.opcode == .struct_decl);35741 assert(extended.opcode == .struct_decl);
35684 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);35742 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
...@@ -36443,7 +36501,7 @@ fn semaStructFields(...@@ -36443,7 +36501,7 @@ fn semaStructFields(
36443 const decl = mod.declPtr(decl_index);36501 const decl = mod.declPtr(decl_index);
36444 const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace;36502 const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace;
36445 const zir = mod.namespacePtr(namespace_index).file_scope.zir;36503 const zir = mod.namespacePtr(namespace_index).file_scope.zir;
36446 const zir_index = struct_type.zir_index.resolve(ip);36504 const zir_index = struct_type.zir_index.unwrap().?.resolve(ip);
3644736505
36448 const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);36506 const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);
3644936507
...@@ -36714,7 +36772,7 @@ fn semaStructFieldInits(...@@ -36714,7 +36772,7 @@ fn semaStructFieldInits(
36714 const decl = mod.declPtr(decl_index);36772 const decl = mod.declPtr(decl_index);
36715 const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace;36773 const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace;
36716 const zir = mod.namespacePtr(namespace_index).file_scope.zir;36774 const zir = mod.namespacePtr(namespace_index).file_scope.zir;
36717 const zir_index = struct_type.zir_index.resolve(ip);36775 const zir_index = struct_type.zir_index.unwrap().?.resolve(ip);
36718 const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);36776 const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);
3671936777
36720 var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa);36778 var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa);
...@@ -36863,7 +36921,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un...@@ -36863,7 +36921,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
36863 const ip = &mod.intern_pool;36921 const ip = &mod.intern_pool;
36864 const decl_index = union_type.decl;36922 const decl_index = union_type.decl;
36865 const zir = mod.namespacePtr(union_type.namespace).file_scope.zir;36923 const zir = mod.namespacePtr(union_type.namespace).file_scope.zir;
36866 const zir_index = union_type.zir_index.resolve(ip);36924 const zir_index = union_type.zir_index.unwrap().?.resolve(ip);
36867 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;36925 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
36868 assert(extended.opcode == .union_decl);36926 assert(extended.opcode == .union_decl);
36869 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);36927 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
...@@ -37307,6 +37365,7 @@ fn generateUnionTagTypeNumbered(...@@ -37307,6 +37365,7 @@ fn generateUnionTagTypeNumbered(
37307 .names = enum_field_names,37365 .names = enum_field_names,
37308 .values = enum_field_vals,37366 .values = enum_field_vals,
37309 .tag_mode = .explicit,37367 .tag_mode = .explicit,
37368 .zir_index = .none,
37310 });37369 });
3731137370
37312 new_decl.ty = Type.type;37371 new_decl.ty = Type.type;
...@@ -37357,6 +37416,7 @@ fn generateUnionTagTypeSimple(...@@ -37357,6 +37416,7 @@ fn generateUnionTagTypeSimple(
37357 .names = enum_field_names,37416 .names = enum_field_names,
37358 .values = &.{},37417 .values = &.{},
37359 .tag_mode = .auto,37418 .tag_mode = .auto,
37419 .zir_index = .none,
37360 });37420 });
3736137421
37362 const new_decl = mod.declPtr(new_decl_index);37422 const new_decl = mod.declPtr(new_decl_index);
...@@ -38870,3 +38930,13 @@ fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type {...@@ -38870,3 +38930,13 @@ fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type {
38870 }38930 }
38871 return sema.mod.ptrType(info);38931 return sema.mod.ptrType(info);
38872}38932}
38933
38934pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
38935 const depender = InternPool.Depender.wrap(
38936 if (sema.owner_func_index != .none)
38937 .{ .func = sema.owner_func_index }
38938 else
38939 .{ .decl = sema.owner_decl_index },
38940 );
38941 try sema.mod.intern_pool.addDependency(sema.gpa, depender, dependee);
38942}
src/type.zig+12
...@@ -4,6 +4,7 @@ const Value = @import("value.zig").Value;...@@ -4,6 +4,7 @@ const Value = @import("value.zig").Value;
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const Target = std.Target;5const Target = std.Target;
6const Module = @import("Module.zig");6const Module = @import("Module.zig");
7const Zcu = Module;
7const log = std.log.scoped(.Type);8const log = std.log.scoped(.Type);
8const target_util = @import("target.zig");9const target_util = @import("target.zig");
9const TypedValue = @import("TypedValue.zig");10const TypedValue = @import("TypedValue.zig");
...@@ -3228,6 +3229,17 @@ pub const Type = struct {...@@ -3228,6 +3229,17 @@ pub const Type = struct {
3228 };3229 };
3229 }3230 }
32303231
3232 pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {
3233 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
3234 inline .struct_type,
3235 .union_type,
3236 .enum_type,
3237 .opaque_type,
3238 => |info| info.zir_index.unwrap(),
3239 else => null,
3240 };
3241 }
3242
3231 pub const @"u1": Type = .{ .ip_index = .u1_type };3243 pub const @"u1": Type = .{ .ip_index = .u1_type };
3232 pub const @"u8": Type = .{ .ip_index = .u8_type };3244 pub const @"u8": Type = .{ .ip_index = .u8_type };
3233 pub const @"u16": Type = .{ .ip_index = .u16_type };3245 pub const @"u16": Type = .{ .ip_index = .u16_type };