| author | |
| committer | |
| log | 7f4bd247c7735ccf277c9bba42222e014cacf856 |
| tree | b47acb0631fc101995b03dd415efe587cec9738b |
| parent | a1b607acb5c1e9dd03760efd7078185e7628b29d |
| signature |
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 | }; |
| 2812 | 2819 | ||
| ... | @@ -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 occur | 2821 | /// 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. |
| 2816 | pub fn saveState(comp: *Compilation) !void { | 2823 | pub 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; |
| 2819 | 2826 | ||
| 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())); |
| 2840 | 2854 | ||
| 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 errors | 2869 | // TODO: compilation errors |
| 2842 | // TODO: files | 2870 | // TODO: files |
| 2843 | // TODO: namespaces | 2871 | // 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. |
| 59 | tracked_insts: std.AutoArrayHashMapUnmanaged(TrackedInst, void) = .{}, | 59 | tracked_insts: std.AutoArrayHashMapUnmanaged(TrackedInst, void) = .{}, |
| 60 | 60 | ||
| 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. | ||
| 67 | src_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. | ||
| 70 | decl_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. | ||
| 74 | namespace_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. | ||
| 77 | namespace_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. | ||
| 82 | first_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. | ||
| 88 | dep_entries: std.ArrayListUnmanaged(DepEntry) = .{}, | ||
| 89 | /// Stores unused indices in `dep_entries` which can be reused without a full | ||
| 90 | /// garbage collection pass. | ||
| 91 | free_dep_entries: std.ArrayListUnmanaged(DepEntry.Index) = .{}, | ||
| 92 | |||
| 61 | pub const TrackedInst = extern struct { | 93 | pub 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 | }; |
| 75 | 120 | ||
| ... | @@ -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 | } |
| 84 | 129 | ||
| 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. | ||
| 133 | pub 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 | |||
| 168 | pub const Dependee = union(enum) { | ||
| 169 | src_hash: TrackedInst.Index, | ||
| 170 | decl_val: DeclIndex, | ||
| 171 | namespace: TrackedInst.Index, | ||
| 172 | namespace_name: NamespaceNameKey, | ||
| 173 | }; | ||
| 174 | |||
| 175 | pub 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 | |||
| 201 | pub 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 | |||
| 212 | pub 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 | |||
| 232 | pub 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. | ||
| 283 | pub 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 | |||
| 290 | pub 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 | |||
| 85 | const FieldMap = std.ArrayHashMapUnmanaged(void, void, std.array_hash_map.AutoContext(void), false); | 326 | const FieldMap = std.ArrayHashMapUnmanaged(void, void, std.array_hash_map.AutoContext(void), false); |
| 86 | 327 | ||
| 87 | const builtin = @import("builtin"); | 328 | const 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 | }; |
| 432 | 674 | ||
| 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 | } |
| 685 | 927 | ||
| 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, |
| 804 | 1046 | ||
| 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` when | 1131 | /// 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, | ||
| 892 | 1135 | ||
| 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, | ||
| 956 | 1200 | ||
| 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 | } |
| 967 | 1212 | ||
| ... | @@ -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 | } |
| 2004 | 2249 | ||
| 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, |
| 3103 | 3348 | ||
| 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_inits | 3366 | /// 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_resolved | 3413 | /// 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 because | 3768 | /// 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 | }; |
| 3527 | 3773 | ||
| 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 | }; |
| 3542 | 3789 | ||
| 3543 | pub const PackedU64 = packed struct(u64) { | 3790 | pub 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 { |
| 3759 | 4006 | ||
| 3760 | ip.tracked_insts.deinit(gpa); | 4007 | ip.tracked_insts.deinit(gpa); |
| 3761 | 4008 | ||
| 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 | } |
| 3764 | 4021 | ||
| ... | @@ -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 | } |
| 4498 | 4757 | ||
| ... | @@ -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 | }); |
| 6268 | 6528 | ||
| 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 | }); |
| 6318 | 6579 | ||
| 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 | }; |
| 6343 | 6605 | ||
| 6344 | pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Error!Index { | 6606 | pub 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)), |
| 6511 | 6777 | ||
| 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), |
| 6587 | 6854 | ||
| 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. |
| 150 | generation: u32 = 0, | 150 | generation: u32 = 0, |
| 151 | 151 | ||
| 152 | /// Value is the number of PO dependencies of this Depender. | ||
| 153 | potentially_outdated: std.AutoArrayHashMapUnmanaged(InternPool.Depender, u32) = .{}, | ||
| 154 | outdated: std.AutoArrayHashMapUnmanaged(InternPool.Depender, void) = .{}, | ||
| 155 | |||
| 152 | stage1_flags: packed struct { | 156 | stage1_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 | } |
| 682 | 686 | ||
| 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, |
| 840 | 836 | ||
| 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 ZIR | 838 | /// This is only populated when a previously successful ZIR |
| 851 | /// newly introduces compile errors during an update. When ZIR is | 839 | /// 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 { |
| 2498 | 2484 | ||
| 2499 | zcu.global_error_set.deinit(gpa); | 2485 | zcu.global_error_set.deinit(gpa); |
| 2500 | 2486 | ||
| 2487 | zcu.potentially_outdated.deinit(gpa); | ||
| 2488 | |||
| 2501 | zcu.test_functions.deinit(gpa); | 2489 | zcu.test_functions.deinit(gpa); |
| 2502 | 2490 | ||
| 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 | } |
| 2857 | 2845 | ||
| 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 succeeded | 2853 | |
| 2876 | // ZIR. We must mark it outdated since we have already tried to | 2854 | 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 | } |
| 2882 | 2861 | ||
| ... | @@ -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 | } |
| 2952 | 2931 | ||
| 2932 | /// This is called from the AstGen thread pool, so must acquire | ||
| 2933 | /// the Compilation mutex when acting on shared state. | ||
| 2953 | fn updateZirRefs(zcu: *Module, file: *File, old_zir: Zir) !void { | 2934 | fn 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; | ||
| 2955 | 2937 | ||
| 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); |
| 2958 | 2940 | ||
| 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); | ||
| 2960 | 2945 | ||
| 2961 | // TODO: this should be done after all AstGen workers complete, to avoid | 2946 | // 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 mechanism | 2953 | // 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 | |||
| 3032 | pub 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 | } |
| 2971 | 3046 | ||
| 3047 | /// Given a Decl which is newly outdated or PO, mark all dependers which depend | ||
| 3048 | /// on its tyval as PO. | ||
| 3049 | fn 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 | |||
| 2972 | pub fn mapOldZirToNew( | 3068 | pub 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 | }; |
| 3537 | 3633 | ||
| 3634 | mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .decl = decl_index })); | ||
| 3635 | |||
| 3538 | decl.analysis = .in_progress; | 3636 | decl.analysis = .in_progress; |
| 3539 | 3637 | ||
| 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(); |
| 3566 | 3664 | ||
| 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)); |
| 3568 | 3669 | ||
| 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); |
| 4364 | 4465 | ||
| 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(); |
| 4367 | 4470 |
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); |
| 2791 | 2791 | ||
| 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); |
| 2975 | 2981 | ||
| 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 | .auto | 3020 | .auto |
| 3009 | else | 3021 | 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); |
| 3227 | 3240 | ||
| 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); |
| 3320 | 3339 | ||
| 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 compilation | 3359 | // 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)).?; |
| 7892 | 7918 | ||
| 7919 | try sema.declareDependency(.{ .src_hash = generic_owner_func.zir_body_inst }); | ||
| 7920 | |||
| 7893 | // Even though there may already be a generic instantiation corresponding | 7921 | // Even though there may already be a generic instantiation corresponding |
| 7894 | // to this callsite, we must evaluate the expressions of the generic | 7922 | // 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 | }); |
| 13595 | 13623 | ||
| 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 | } | ||
| 13597 | 13631 | ||
| 13598 | const namespace = container_type.getNamespaceIndex(mod).unwrap() orelse | 13632 | 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).?; |
| 17449 | 17483 | ||
| 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 | else | 21351 | 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 compilation | 21356 | // 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 compilation | 21454 | // 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(); |
| 26839 | 26880 | ||
| 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(); |
| 27062 | 27110 | ||
| 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; |
| 31133 | 31189 | ||
| 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 |
| 32382 | 32438 | ||
| 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 | }; |
| 35680 | 35738 | ||
| 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); |
| 36447 | 36505 | ||
| 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); |
| 36449 | 36507 | ||
| ... | @@ -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); |
| 36719 | 36777 | ||
| 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 | }); |
| 37311 | 37370 | ||
| 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 | }); |
| 37361 | 37421 | ||
| 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 | |||
| 38934 | pub 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; |
| 4 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 5 | const Target = std.Target; | 5 | const Target = std.Target; |
| 6 | const Module = @import("Module.zig"); | 6 | const Module = @import("Module.zig"); |
| 7 | const Zcu = Module; | ||
| 7 | const log = std.log.scoped(.Type); | 8 | const log = std.log.scoped(.Type); |
| 8 | const target_util = @import("target.zig"); | 9 | const target_util = @import("target.zig"); |
| 9 | const TypedValue = @import("TypedValue.zig"); | 10 | const TypedValue = @import("TypedValue.zig"); |
| ... | @@ -3228,6 +3229,17 @@ pub const Type = struct { | ... | @@ -3228,6 +3229,17 @@ pub const Type = struct { |
| 3228 | }; | 3229 | }; |
| 3229 | } | 3230 | } |
| 3230 | 3231 | ||
| 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 }; |