| author | |
| committer | |
| log | 0978566db8b7ed2b730cf01a7d359e9b52ec66ec |
| tree | 5cc2665bd7447dbd6a681dde31ff0efce79eac50 |
| parent | 01cc1a58675806b72580e094609f8dde0019d6ea |
My changes to how incremental compilation handles container types mean
that, at least for now, it is possible for the ZIR `.main_struct_inst`
of a source file to be lost (this happens if the number of top-level
fields in a file changes for instance). I missed a few things which
needed changing to account for this, which could lead to crashes with
certain (trivial) changes---oops!
Adds two new incremental test cases. They are currently disabled for
wasm32-wasi-selfhosted because they both trigger a crash in the WASM
backend.8 files changed, 265 insertions(+), 39 deletions(-)
src/Compilation.zig+4-4| ... | @@ -3649,7 +3649,7 @@ const Header = extern struct { | ... | @@ -3649,7 +3649,7 @@ const Header = extern struct { |
| 3649 | type_layout_deps_len: u32, | 3649 | type_layout_deps_len: u32, |
| 3650 | struct_defaults_deps_len: u32, | 3650 | struct_defaults_deps_len: u32, |
| 3651 | func_ies_deps_len: u32, | 3651 | func_ies_deps_len: u32, |
| 3652 | zon_file_deps_len: u32, | 3652 | source_file_deps_len: u32, |
| 3653 | embed_file_deps_len: u32, | 3653 | embed_file_deps_len: u32, |
| 3654 | namespace_deps_len: u32, | 3654 | namespace_deps_len: u32, |
| 3655 | namespace_name_deps_len: u32, | 3655 | namespace_name_deps_len: u32, |
| ... | @@ -3699,7 +3699,7 @@ pub fn saveState(comp: *Compilation) !void { | ... | @@ -3699,7 +3699,7 @@ pub fn saveState(comp: *Compilation) !void { |
| 3699 | .type_layout_deps_len = @intCast(ip.type_layout_deps.count()), | 3699 | .type_layout_deps_len = @intCast(ip.type_layout_deps.count()), |
| 3700 | .struct_defaults_deps_len = @intCast(ip.struct_defaults_deps.count()), | 3700 | .struct_defaults_deps_len = @intCast(ip.struct_defaults_deps.count()), |
| 3701 | .func_ies_deps_len = @intCast(ip.func_ies_deps.count()), | 3701 | .func_ies_deps_len = @intCast(ip.func_ies_deps.count()), |
| 3702 | .zon_file_deps_len = @intCast(ip.zon_file_deps.count()), | 3702 | .source_file_deps_len = @intCast(ip.source_file_deps.count()), |
| 3703 | .embed_file_deps_len = @intCast(ip.embed_file_deps.count()), | 3703 | .embed_file_deps_len = @intCast(ip.embed_file_deps.count()), |
| 3704 | .namespace_deps_len = @intCast(ip.namespace_deps.count()), | 3704 | .namespace_deps_len = @intCast(ip.namespace_deps.count()), |
| 3705 | .namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()), | 3705 | .namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()), |
| ... | @@ -3738,8 +3738,8 @@ pub fn saveState(comp: *Compilation) !void { | ... | @@ -3738,8 +3738,8 @@ pub fn saveState(comp: *Compilation) !void { |
| 3738 | addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.values())); | 3738 | addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.values())); |
| 3739 | addBuf(&bufs, @ptrCast(ip.func_ies_deps.keys())); | 3739 | addBuf(&bufs, @ptrCast(ip.func_ies_deps.keys())); |
| 3740 | addBuf(&bufs, @ptrCast(ip.func_ies_deps.values())); | 3740 | addBuf(&bufs, @ptrCast(ip.func_ies_deps.values())); |
| 3741 | addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys())); | 3741 | addBuf(&bufs, @ptrCast(ip.source_file_deps.keys())); |
| 3742 | addBuf(&bufs, @ptrCast(ip.zon_file_deps.values())); | 3742 | addBuf(&bufs, @ptrCast(ip.source_file_deps.values())); |
| 3743 | addBuf(&bufs, @ptrCast(ip.embed_file_deps.keys())); | 3743 | addBuf(&bufs, @ptrCast(ip.embed_file_deps.keys())); |
| 3744 | addBuf(&bufs, @ptrCast(ip.embed_file_deps.values())); | 3744 | addBuf(&bufs, @ptrCast(ip.embed_file_deps.values())); |
| 3745 | addBuf(&bufs, @ptrCast(ip.namespace_deps.keys())); | 3745 | addBuf(&bufs, @ptrCast(ip.namespace_deps.keys())); |
src/IncrementalDebugServer.zig+1-1| ... | @@ -305,7 +305,7 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const | ... | @@ -305,7 +305,7 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const |
| 305 | for (unit_info.deps.items, 0..) |dependee, i| { | 305 | for (unit_info.deps.items, 0..) |dependee, i| { |
| 306 | try w.print("[{d}] ", .{i}); | 306 | try w.print("[{d}] ", .{i}); |
| 307 | switch (dependee) { | 307 | switch (dependee) { |
| 308 | .src_hash, .namespace, .namespace_name, .zon_file, .embed_file => try w.print("{f}", .{zcu.fmtDependee(dependee)}), | 308 | .src_hash, .namespace, .namespace_name, .source_file, .embed_file => try w.print("{f}", .{zcu.fmtDependee(dependee)}), |
| 309 | .nav_val, .nav_ty => |nav| try w.print("{t} {d}", .{ dependee, @intFromEnum(nav) }), | 309 | .nav_val, .nav_ty => |nav| try w.print("{t} {d}", .{ dependee, @intFromEnum(nav) }), |
| 310 | .type_layout, .struct_defaults, .func_ies => |ip_index| try w.print("{t} {d}", .{ dependee, @intFromEnum(ip_index) }), | 310 | .type_layout, .struct_defaults, .func_ies => |ip_index| try w.print("{t} {d}", .{ dependee, @intFromEnum(ip_index) }), |
| 311 | .memoized_state => |stage| try w.print("memoized_state {s}", .{@tagName(stage)}), | 311 | .memoized_state => |stage| try w.print("memoized_state {s}", .{@tagName(stage)}), |
src/InternPool.zig+19-14| ... | @@ -57,9 +57,14 @@ type_layout_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), | ... | @@ -57,9 +57,14 @@ type_layout_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), |
| 57 | /// Dependencies on the resolved default field values of a `struct` type. | 57 | /// Dependencies on the resolved default field values of a `struct` type. |
| 58 | /// Value is index into `dep_entries` of the first dependency on this type's inits. | 58 | /// Value is index into `dep_entries` of the first dependency on this type's inits. |
| 59 | struct_defaults_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), | 59 | struct_defaults_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), |
| 60 | /// Dependencies on a ZON file. Triggered by `@import` of ZON. | 60 | /// Dependencies on a Zig or ZON source file. Triggered by `@import`. |
| 61 | /// Value is index into `dep_entries` of the first dependency on this ZON file. | 61 | /// * For ZON source files, the dependency is invalidated if the file changes at all. The `@import` |
| 62 | zon_file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index), | 62 | /// must be re-analyzed to return the new data structure. |
| 63 | /// * For Zig source files, the dependency is invalidated if the file's root struct type changes | ||
| 64 | /// (which can only happen because the `.main_struct_inst` got lost). The `@import` must be | ||
| 65 | /// re-analyzed to return the new type. | ||
| 66 | /// Value is index into `dep_entries` of the first dependency on this Zig/ZON file. | ||
| 67 | source_file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index), | ||
| 63 | /// Dependencies on an embedded file. | 68 | /// Dependencies on an embedded file. |
| 64 | /// Introduced by `@embedFile`; invalidated when the file changes. | 69 | /// Introduced by `@embedFile`; invalidated when the file changes. |
| 65 | /// Value is index into `dep_entries` of the first dependency on this `Zcu.EmbedFile`. | 70 | /// Value is index into `dep_entries` of the first dependency on this `Zcu.EmbedFile`. |
| ... | @@ -112,7 +117,7 @@ pub const empty: InternPool = .{ | ... | @@ -112,7 +117,7 @@ pub const empty: InternPool = .{ |
| 112 | .func_ies_deps = .empty, | 117 | .func_ies_deps = .empty, |
| 113 | .type_layout_deps = .empty, | 118 | .type_layout_deps = .empty, |
| 114 | .struct_defaults_deps = .empty, | 119 | .struct_defaults_deps = .empty, |
| 115 | .zon_file_deps = .empty, | 120 | .source_file_deps = .empty, |
| 116 | .embed_file_deps = .empty, | 121 | .embed_file_deps = .empty, |
| 117 | .namespace_deps = .empty, | 122 | .namespace_deps = .empty, |
| 118 | .namespace_name_deps = .empty, | 123 | .namespace_name_deps = .empty, |
| ... | @@ -859,7 +864,7 @@ pub const Dependee = union(enum) { | ... | @@ -859,7 +864,7 @@ pub const Dependee = union(enum) { |
| 859 | func_ies: Index, | 864 | func_ies: Index, |
| 860 | type_layout: Index, | 865 | type_layout: Index, |
| 861 | struct_defaults: Index, | 866 | struct_defaults: Index, |
| 862 | zon_file: FileIndex, | 867 | source_file: FileIndex, |
| 863 | embed_file: Zcu.EmbedFile.Index, | 868 | embed_file: Zcu.EmbedFile.Index, |
| 864 | namespace: TrackedInst.Index, | 869 | namespace: TrackedInst.Index, |
| 865 | namespace_name: NamespaceNameKey, | 870 | namespace_name: NamespaceNameKey, |
| ... | @@ -913,7 +918,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI | ... | @@ -913,7 +918,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI |
| 913 | .func_ies => |x| ip.func_ies_deps.get(x), | 918 | .func_ies => |x| ip.func_ies_deps.get(x), |
| 914 | .type_layout => |x| ip.type_layout_deps.get(x), | 919 | .type_layout => |x| ip.type_layout_deps.get(x), |
| 915 | .struct_defaults => |x| ip.struct_defaults_deps.get(x), | 920 | .struct_defaults => |x| ip.struct_defaults_deps.get(x), |
| 916 | .zon_file => |x| ip.zon_file_deps.get(x), | 921 | .source_file => |x| ip.source_file_deps.get(x), |
| 917 | .embed_file => |x| ip.embed_file_deps.get(x), | 922 | .embed_file => |x| ip.embed_file_deps.get(x), |
| 918 | .namespace => |x| ip.namespace_deps.get(x), | 923 | .namespace => |x| ip.namespace_deps.get(x), |
| 919 | .namespace_name => |x| ip.namespace_name_deps.get(x), | 924 | .namespace_name => |x| ip.namespace_name_deps.get(x), |
| ... | @@ -988,7 +993,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend | ... | @@ -988,7 +993,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend |
| 988 | .func_ies => ip.func_ies_deps, | 993 | .func_ies => ip.func_ies_deps, |
| 989 | .type_layout => ip.type_layout_deps, | 994 | .type_layout => ip.type_layout_deps, |
| 990 | .struct_defaults => ip.struct_defaults_deps, | 995 | .struct_defaults => ip.struct_defaults_deps, |
| 991 | .zon_file => ip.zon_file_deps, | 996 | .source_file => ip.source_file_deps, |
| 992 | .embed_file => ip.embed_file_deps, | 997 | .embed_file => ip.embed_file_deps, |
| 993 | .namespace => ip.namespace_deps, | 998 | .namespace => ip.namespace_deps, |
| 994 | .namespace_name => ip.namespace_name_deps, | 999 | .namespace_name => ip.namespace_name_deps, |
| ... | @@ -6477,7 +6482,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator, io: Io) void { | ... | @@ -6477,7 +6482,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator, io: Io) void { |
| 6477 | ip.func_ies_deps.deinit(gpa); | 6482 | ip.func_ies_deps.deinit(gpa); |
| 6478 | ip.type_layout_deps.deinit(gpa); | 6483 | ip.type_layout_deps.deinit(gpa); |
| 6479 | ip.struct_defaults_deps.deinit(gpa); | 6484 | ip.struct_defaults_deps.deinit(gpa); |
| 6480 | ip.zon_file_deps.deinit(gpa); | 6485 | ip.source_file_deps.deinit(gpa); |
| 6481 | ip.embed_file_deps.deinit(gpa); | 6486 | ip.embed_file_deps.deinit(gpa); |
| 6482 | ip.namespace_deps.deinit(gpa); | 6487 | ip.namespace_deps.deinit(gpa); |
| 6483 | ip.namespace_name_deps.deinit(gpa); | 6488 | ip.namespace_name_deps.deinit(gpa); |
| ... | @@ -10643,7 +10648,7 @@ fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void { | ... | @@ -10643,7 +10648,7 @@ fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void { |
| 10643 | const func_ies_deps_len = ip.func_ies_deps.count(); | 10648 | const func_ies_deps_len = ip.func_ies_deps.count(); |
| 10644 | const type_layout_deps_len = ip.type_layout_deps.count(); | 10649 | const type_layout_deps_len = ip.type_layout_deps.count(); |
| 10645 | const struct_defaults_deps_len = ip.struct_defaults_deps.count(); | 10650 | const struct_defaults_deps_len = ip.struct_defaults_deps.count(); |
| 10646 | const zon_file_deps_len = ip.zon_file_deps.count(); | 10651 | const source_file_deps_len = ip.source_file_deps.count(); |
| 10647 | const embed_file_deps_len = ip.embed_file_deps.count(); | 10652 | const embed_file_deps_len = ip.embed_file_deps.count(); |
| 10648 | const namespace_deps_len = ip.namespace_deps.count(); | 10653 | const namespace_deps_len = ip.namespace_deps.count(); |
| 10649 | const namespace_name_deps_len = ip.namespace_name_deps.count(); | 10654 | const namespace_name_deps_len = ip.namespace_name_deps.count(); |
| ... | @@ -10654,7 +10659,7 @@ fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void { | ... | @@ -10654,7 +10659,7 @@ fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void { |
| 10654 | const func_ies_deps_size = func_ies_deps_len * 8; | 10659 | const func_ies_deps_size = func_ies_deps_len * 8; |
| 10655 | const type_layout_deps_size = type_layout_deps_len * 8; | 10660 | const type_layout_deps_size = type_layout_deps_len * 8; |
| 10656 | const struct_defaults_deps_size = struct_defaults_deps_len * 8; | 10661 | const struct_defaults_deps_size = struct_defaults_deps_len * 8; |
| 10657 | const zon_file_deps_size = zon_file_deps_len * 8; | 10662 | const source_file_deps_size = source_file_deps_len * 8; |
| 10658 | const embed_file_deps_size = embed_file_deps_len * 8; | 10663 | const embed_file_deps_size = embed_file_deps_len * 8; |
| 10659 | const namespace_deps_size = namespace_deps_len * 8; | 10664 | const namespace_deps_size = namespace_deps_len * 8; |
| 10660 | const namespace_name_deps_size = namespace_name_deps_len * (@sizeOf(NamespaceNameKey) + 4); | 10665 | const namespace_name_deps_size = namespace_name_deps_len * (@sizeOf(NamespaceNameKey) + 4); |
| ... | @@ -10668,14 +10673,14 @@ fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void { | ... | @@ -10668,14 +10673,14 @@ fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void { |
| 10668 | \\ {d} func_ies: {d} bytes | 10673 | \\ {d} func_ies: {d} bytes |
| 10669 | \\ {d} type_layout: {d} bytes | 10674 | \\ {d} type_layout: {d} bytes |
| 10670 | \\ {d} struct_defaults: {d} bytes | 10675 | \\ {d} struct_defaults: {d} bytes |
| 10671 | \\ {d} zon_file: {d} bytes | 10676 | \\ {d} source_file: {d} bytes |
| 10672 | \\ {d} embed_file: {d} bytes | 10677 | \\ {d} embed_file: {d} bytes |
| 10673 | \\ {d} namespace: {d} bytes | 10678 | \\ {d} namespace: {d} bytes |
| 10674 | \\ {d} namespace_name: {d} bytes | 10679 | \\ {d} namespace_name: {d} bytes |
| 10675 | \\ | 10680 | \\ |
| 10676 | , .{ | 10681 | , .{ |
| 10677 | dep_entries_size + src_hash_deps_size + nav_val_deps_size + nav_ty_deps_size + | 10682 | dep_entries_size + src_hash_deps_size + nav_val_deps_size + nav_ty_deps_size + |
| 10678 | func_ies_deps_size + type_layout_deps_size + struct_defaults_deps_size + zon_file_deps_size + | 10683 | func_ies_deps_size + type_layout_deps_size + struct_defaults_deps_size + source_file_deps_size + |
| 10679 | embed_file_deps_size + namespace_deps_size + namespace_name_deps_size, | 10684 | embed_file_deps_size + namespace_deps_size + namespace_name_deps_size, |
| 10680 | dep_entries_len, | 10685 | dep_entries_len, |
| 10681 | dep_entries_size, | 10686 | dep_entries_size, |
| ... | @@ -10691,8 +10696,8 @@ fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void { | ... | @@ -10691,8 +10696,8 @@ fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void { |
| 10691 | type_layout_deps_size, | 10696 | type_layout_deps_size, |
| 10692 | struct_defaults_deps_len, | 10697 | struct_defaults_deps_len, |
| 10693 | struct_defaults_deps_size, | 10698 | struct_defaults_deps_size, |
| 10694 | zon_file_deps_len, | 10699 | source_file_deps_len, |
| 10695 | zon_file_deps_size, | 10700 | source_file_deps_size, |
| 10696 | embed_file_deps_len, | 10701 | embed_file_deps_len, |
| 10697 | embed_file_deps_size, | 10702 | embed_file_deps_size, |
| 10698 | namespace_deps_len, | 10703 | namespace_deps_len, |
src/Sema.zig+2-2| ... | @@ -13011,6 +13011,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -13011,6 +13011,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 13011 | }; | 13011 | }; |
| 13012 | const file_index = result.file; | 13012 | const file_index = result.file; |
| 13013 | const file = zcu.fileByIndex(file_index); | 13013 | const file = zcu.fileByIndex(file_index); |
| 13014 | try sema.declareDependency(.{ .source_file = file_index }); | ||
| 13014 | switch (file.getMode()) { | 13015 | switch (file.getMode()) { |
| 13015 | .zig => { | 13016 | .zig => { |
| 13016 | try pt.ensureFilePopulated(file_index); | 13017 | try pt.ensureFilePopulated(file_index); |
| ... | @@ -13028,8 +13029,6 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -13028,8 +13029,6 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 13028 | if (res_ty.isGenericPoison()) break :b .none; | 13029 | if (res_ty.isGenericPoison()) break :b .none; |
| 13029 | break :b res_ty.toIntern(); | 13030 | break :b res_ty.toIntern(); |
| 13030 | }; | 13031 | }; |
| 13031 | |||
| 13032 | try sema.declareDependency(.{ .zon_file = file_index }); | ||
| 13033 | const interned = try LowerZon.run( | 13032 | const interned = try LowerZon.run( |
| 13034 | sema, | 13033 | sema, |
| 13035 | file, | 13034 | file, |
| ... | @@ -34084,6 +34083,7 @@ pub fn analyzeMemoizedState(sema: *Sema, stage: InternPool.MemoizedStateStage) C | ... | @@ -34084,6 +34083,7 @@ pub fn analyzeMemoizedState(sema: *Sema, stage: InternPool.MemoizedStateStage) C |
| 34084 | // Get the main struct type of the root source file of `std`. No need for a reference entry | 34083 | // Get the main struct type of the root source file of `std`. No need for a reference entry |
| 34085 | // because `std` is always an analysis root. | 34084 | // because `std` is always an analysis root. |
| 34086 | const std_file_index = zcu.module_roots.get(zcu.std_mod).?.unwrap().?; | 34085 | const std_file_index = zcu.module_roots.get(zcu.std_mod).?.unwrap().?; |
| 34086 | try sema.declareDependency(.{ .source_file = std_file_index }); | ||
| 34087 | try pt.ensureFilePopulated(std_file_index); | 34087 | try pt.ensureFilePopulated(std_file_index); |
| 34088 | const std_type: Type = .fromInterned(zcu.fileRootType(std_file_index)); | 34088 | const std_type: Type = .fromInterned(zcu.fileRootType(std_file_index)); |
| 34089 | break :block .{ | 34089 | break :block .{ |
src/Zcu.zig+3-3| ... | @@ -1014,7 +1014,7 @@ pub const File = struct { | ... | @@ -1014,7 +1014,7 @@ pub const File = struct { |
| 1014 | /// changed -- this field is just a simple boolean. | 1014 | /// changed -- this field is just a simple boolean. |
| 1015 | /// | 1015 | /// |
| 1016 | /// When `zoir` is updated, this field is set to `true`. In `updateZirRefs`, if this is `true`, | 1016 | /// When `zoir` is updated, this field is set to `true`. In `updateZirRefs`, if this is `true`, |
| 1017 | /// we invalidate the corresponding `zon_file` dependency, and reset it to `false`. | 1017 | /// we invalidate the corresponding `source_file` dependency, and reset it to `false`. |
| 1018 | zoir_invalidated: bool, | 1018 | zoir_invalidated: bool, |
| 1019 | 1019 | ||
| 1020 | pub const Path = struct { | 1020 | pub const Path = struct { |
| ... | @@ -4496,9 +4496,9 @@ fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void | ... | @@ -4496,9 +4496,9 @@ fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void |
| 4496 | const fqn = ip.getNav(ip.indexToKey(ip_index).func.owner_nav).fqn; | 4496 | const fqn = ip.getNav(ip.indexToKey(ip_index).func.owner_nav).fqn; |
| 4497 | return writer.print("func_ies('{f}')", .{fqn.fmt(ip)}); | 4497 | return writer.print("func_ies('{f}')", .{fqn.fmt(ip)}); |
| 4498 | }, | 4498 | }, |
| 4499 | .zon_file => |file| { | 4499 | .source_file => |file| { |
| 4500 | const file_path = zcu.fileByIndex(file).path; | 4500 | const file_path = zcu.fileByIndex(file).path; |
| 4501 | return writer.print("zon_file('{f}')", .{file_path.fmt(zcu.comp)}); | 4501 | return writer.print("source_file('{f}')", .{file_path.fmt(zcu.comp)}); |
| 4502 | }, | 4502 | }, |
| 4503 | .embed_file => |ef_idx| { | 4503 | .embed_file => |ef_idx| { |
| 4504 | const ef = ef_idx.get(zcu); | 4504 | const ef = ef_idx.get(zcu); |
src/Zcu/PerThread.zig+37-15| ... | @@ -838,7 +838,7 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void { | ... | @@ -838,7 +838,7 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void { |
| 838 | .zig => {}, // logic below | 838 | .zig => {}, // logic below |
| 839 | .zon => { | 839 | .zon => { |
| 840 | if (file.zoir_invalidated) { | 840 | if (file.zoir_invalidated) { |
| 841 | try zcu.markDependeeOutdated(.not_marked_po, .{ .zon_file = file_index }); | 841 | try zcu.markDependeeOutdated(.not_marked_po, .{ .source_file = file_index }); |
| 842 | file.zoir_invalidated = false; | 842 | file.zoir_invalidated = false; |
| 843 | } | 843 | } |
| 844 | continue; | 844 | continue; |
| ... | @@ -988,8 +988,8 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void { | ... | @@ -988,8 +988,8 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void { |
| 988 | // be re-analyzed (causing the struct's namespace to be re-scanned). It's fine to do this | 988 | // be re-analyzed (causing the struct's namespace to be re-scanned). It's fine to do this |
| 989 | // now because this work is fast (no actual Sema work is happening, we're just updating the | 989 | // now because this work is fast (no actual Sema work is happening, we're just updating the |
| 990 | // namespace contents). We must do this after updating ZIR refs above, since `scanNamespace` | 990 | // namespace contents). We must do this after updating ZIR refs above, since `scanNamespace` |
| 991 | // will track some instructions. | 991 | // calls will track some instructions. |
| 992 | try pt.updateFileNamespace(file_index); | 992 | try pt.updateFileRootStructType(file_index); |
| 993 | } | 993 | } |
| 994 | } | 994 | } |
| 995 | 995 | ||
| ... | @@ -2350,27 +2350,49 @@ fn analyzeFuncBody( | ... | @@ -2350,27 +2350,49 @@ fn analyzeFuncBody( |
| 2350 | return .{ .ies_outdated = ies_outdated }; | 2350 | return .{ .ies_outdated = ies_outdated }; |
| 2351 | } | 2351 | } |
| 2352 | 2352 | ||
| 2353 | /// Re-scan the namespace of a file's root struct type on an incremental update. | 2353 | /// The given file has been modified on this incremental update, so if it has a populated root |
| 2354 | /// The file must have successfully populated ZIR. | 2354 | /// struct type, either re-scan its namespace, or clear it and invalidate dependencies if the |
| 2355 | /// If the file's root struct type is not populated (the file is unreferenced), nothing is done. | 2355 | /// type is no longer valid. See comments in body for more details. |
| 2356 | /// This is called by `updateZirRefs` for all updated files before the main work loop. | 2356 | /// |
| 2357 | /// This function does not perform any semantic analysis. | 2357 | /// Called by `updateZirRefs` for all updated Zig source files before the main update loop. |
| 2358 | fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!void { | 2358 | /// |
| 2359 | /// Asserts that the file has successfully populated ZIR. | ||
| 2360 | fn updateFileRootStructType(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!void { | ||
| 2359 | const zcu = pt.zcu; | 2361 | const zcu = pt.zcu; |
| 2362 | const ip = &zcu.intern_pool; | ||
| 2360 | 2363 | ||
| 2361 | const file = zcu.fileByIndex(file_index); | 2364 | const file = zcu.fileByIndex(file_index); |
| 2362 | const file_root_type = zcu.fileRootType(file_index); | 2365 | const file_root_type = zcu.fileRootType(file_index); |
| 2363 | if (file_root_type == .none) return; | 2366 | if (file_root_type == .none) { |
| 2367 | // We haven't analyzed any `@import` of this file so far, so there's nothing to update. If | ||
| 2368 | // an `@import` gets analyzed, then `ensureFilePopulated` will create the root struct type | ||
| 2369 | // and scan the namespace. | ||
| 2370 | return; | ||
| 2371 | } | ||
| 2364 | 2372 | ||
| 2365 | log.debug("updateFileNamespace mod={s} sub_file_path={s}", .{ | 2373 | const loaded_struct = ip.loadStructType(file_root_type); |
| 2374 | |||
| 2375 | log.debug("updateFileRootStructType mod={s} sub_file_path={s}", .{ | ||
| 2366 | file.mod.?.fully_qualified_name, | 2376 | file.mod.?.fully_qualified_name, |
| 2367 | file.sub_file_path, | 2377 | file.sub_file_path, |
| 2368 | }); | 2378 | }); |
| 2369 | 2379 | ||
| 2370 | const namespace_index = Type.fromInterned(file_root_type).getNamespaceIndex(zcu); | 2380 | if (loaded_struct.zir_index.resolve(ip) == null) { |
| 2371 | const decls = file.zir.?.getStructDecl(.main_struct_inst).decls; | 2381 | // The file's root struct decl has been lost, so a new struct type must be interned at a new |
| 2372 | try pt.scanNamespace(namespace_index, decls); | 2382 | // `InternPool.Index`. Clear the file's root type so that `ensureFilePopulated` will do that |
| 2373 | zcu.namespacePtr(namespace_index).generation = zcu.generation; | 2383 | // work, and invalidate dependencies on this file to force re-analysis of `@import` sites. |
| 2384 | zcu.setFileRootType(file_index, .none); | ||
| 2385 | try zcu.markDependeeOutdated(.not_marked_po, .{ .source_file = file_index }); | ||
| 2386 | } else { | ||
| 2387 | // The existing struct type is valid, but the namespace contents might have changed. For | ||
| 2388 | // most struct types, that would cause the surrounding declaration to be invalidated which | ||
| 2389 | // causes `Sema.zirStructType` (or whatever) to call `ensureNamespaceUpToDate`. However, | ||
| 2390 | // there is no "surrounding declaration" for the root struct type of a Zig source file, so | ||
| 2391 | // update this namespace now. | ||
| 2392 | const decls = file.zir.?.getStructDecl(.main_struct_inst).decls; | ||
| 2393 | try pt.scanNamespace(loaded_struct.namespace, decls); | ||
| 2394 | zcu.namespacePtr(loaded_struct.namespace).generation = zcu.generation; | ||
| 2395 | } | ||
| 2374 | } | 2396 | } |
| 2375 | 2397 | ||
| 2376 | /// Called by AstGen worker threads when an import is seen. If `new_file` is returned, the caller is | 2398 | /// Called by AstGen worker threads when an import is seen. If `new_file` is returned, the caller is |
test/incremental/add_remove_struct_fields created+98| ... | @@ -0,0 +1,98 @@ | ||
| 1 | #target=x86_64-linux-selfhosted | ||
| 2 | #target=x86_64-windows-selfhosted | ||
| 3 | #target=x86_64-linux-cbe | ||
| 4 | #target=x86_64-windows-cbe | ||
| 5 | //#target=wasm32-wasi-selfhosted | ||
| 6 | #update=initial version | ||
| 7 | #file=main.zig | ||
| 8 | const S = struct { x: u8 }; | ||
| 9 | pub fn main(init: std.process.Init) !void { | ||
| 10 | var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); | ||
| 11 | printFieldCount(&stdout_writer.interface) catch |err| switch (err) { | ||
| 12 | error.WriteFailed => return stdout_writer.err.?, | ||
| 13 | }; | ||
| 14 | printOneField(&stdout_writer.interface) catch |err| switch (err) { | ||
| 15 | error.WriteFailed => return stdout_writer.err.?, | ||
| 16 | }; | ||
| 17 | } | ||
| 18 | fn printFieldCount(w: *Writer) Writer.Error!void { | ||
| 19 | try w.print("{d} ", .{@typeInfo(S).@"struct".fields.len}); | ||
| 20 | } | ||
| 21 | fn printOneField(w: *Writer) Writer.Error!void { | ||
| 22 | const val: S = .{ .x = 100 }; | ||
| 23 | try w.print("{d}\n", .{val.x}); | ||
| 24 | } | ||
| 25 | const std = @import("std"); | ||
| 26 | const Writer = std.Io.Writer; | ||
| 27 | #expect_stdout="1 100\n" | ||
| 28 | |||
| 29 | #update=add a field | ||
| 30 | #file=main.zig | ||
| 31 | const S = struct { x: u8, y: u16 = 200 }; | ||
| 32 | pub fn main(init: std.process.Init) !void { | ||
| 33 | var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); | ||
| 34 | printFieldCount(&stdout_writer.interface) catch |err| switch (err) { | ||
| 35 | error.WriteFailed => return stdout_writer.err.?, | ||
| 36 | }; | ||
| 37 | printOneField(&stdout_writer.interface) catch |err| switch (err) { | ||
| 38 | error.WriteFailed => return stdout_writer.err.?, | ||
| 39 | }; | ||
| 40 | } | ||
| 41 | fn printFieldCount(w: *Writer) Writer.Error!void { | ||
| 42 | try w.print("{d} ", .{@typeInfo(S).@"struct".fields.len}); | ||
| 43 | } | ||
| 44 | fn printOneField(w: *Writer) Writer.Error!void { | ||
| 45 | const val: S = .{ .x = 100 }; | ||
| 46 | try w.print("{d}\n", .{val.x}); | ||
| 47 | } | ||
| 48 | const std = @import("std"); | ||
| 49 | const Writer = std.Io.Writer; | ||
| 50 | #expect_stdout="2 100\n" | ||
| 51 | |||
| 52 | #update=remove all fields | ||
| 53 | #file=main.zig | ||
| 54 | const S = struct {}; | ||
| 55 | pub fn main(init: std.process.Init) !void { | ||
| 56 | var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); | ||
| 57 | printFieldCount(&stdout_writer.interface) catch |err| switch (err) { | ||
| 58 | error.WriteFailed => return stdout_writer.err.?, | ||
| 59 | }; | ||
| 60 | printOneField(&stdout_writer.interface) catch |err| switch (err) { | ||
| 61 | error.WriteFailed => return stdout_writer.err.?, | ||
| 62 | }; | ||
| 63 | } | ||
| 64 | fn printFieldCount(w: *Writer) Writer.Error!void { | ||
| 65 | try w.print("{d} ", .{@typeInfo(S).@"struct".fields.len}); | ||
| 66 | } | ||
| 67 | fn printOneField(w: *Writer) Writer.Error!void { | ||
| 68 | const val: S = .{ .x = 100 }; | ||
| 69 | try w.print("{d}\n", .{val.x}); | ||
| 70 | } | ||
| 71 | const std = @import("std"); | ||
| 72 | const Writer = std.Io.Writer; | ||
| 73 | #expect_error=main.zig:15:24: error: no field named 'x' in struct 'main.S' | ||
| 74 | #expect_error=main.zig:1:11: note: struct declared here | ||
| 75 | |||
| 76 | #update=remove reference to non-existent field | ||
| 77 | #file=main.zig | ||
| 78 | const S = struct {}; | ||
| 79 | pub fn main(init: std.process.Init) !void { | ||
| 80 | var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); | ||
| 81 | printFieldCount(&stdout_writer.interface) catch |err| switch (err) { | ||
| 82 | error.WriteFailed => return stdout_writer.err.?, | ||
| 83 | }; | ||
| 84 | printOneField(&stdout_writer.interface) catch |err| switch (err) { | ||
| 85 | error.WriteFailed => return stdout_writer.err.?, | ||
| 86 | }; | ||
| 87 | } | ||
| 88 | fn printFieldCount(w: *Writer) Writer.Error!void { | ||
| 89 | try w.print("{d} ", .{@typeInfo(S).@"struct".fields.len}); | ||
| 90 | } | ||
| 91 | fn printOneField(w: *Writer) Writer.Error!void { | ||
| 92 | //const val: S = .{ .x = 100 }; | ||
| 93 | //try w.print("{d}\n", .{val.x}); | ||
| 94 | try w.writeAll("<no fields>\n"); | ||
| 95 | } | ||
| 96 | const std = @import("std"); | ||
| 97 | const Writer = std.Io.Writer; | ||
| 98 | #expect_stdout="0 <no fields>\n" | ||
test/incremental/add_remove_toplevel_fields created+101| ... | @@ -0,0 +1,101 @@ | ||
| 1 | #target=x86_64-linux-selfhosted | ||
| 2 | #target=x86_64-windows-selfhosted | ||
| 3 | #target=x86_64-linux-cbe | ||
| 4 | #target=x86_64-windows-cbe | ||
| 5 | //#target=wasm32-wasi-selfhosted | ||
| 6 | #update=initial version | ||
| 7 | #file=main.zig | ||
| 8 | const S = @This(); | ||
| 9 | x: u8, | ||
| 10 | pub fn main(init: std.process.Init) !void { | ||
| 11 | var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); | ||
| 12 | printFieldCount(&stdout_writer.interface) catch |err| switch (err) { | ||
| 13 | error.WriteFailed => return stdout_writer.err.?, | ||
| 14 | }; | ||
| 15 | printOneField(&stdout_writer.interface) catch |err| switch (err) { | ||
| 16 | error.WriteFailed => return stdout_writer.err.?, | ||
| 17 | }; | ||
| 18 | } | ||
| 19 | fn printFieldCount(w: *Writer) Writer.Error!void { | ||
| 20 | try w.print("{d} ", .{@typeInfo(S).@"struct".fields.len}); | ||
| 21 | } | ||
| 22 | fn printOneField(w: *Writer) Writer.Error!void { | ||
| 23 | const val: S = .{ .x = 100 }; | ||
| 24 | try w.print("{d}\n", .{val.x}); | ||
| 25 | } | ||
| 26 | const std = @import("std"); | ||
| 27 | const Writer = std.Io.Writer; | ||
| 28 | #expect_stdout="1 100\n" | ||
| 29 | |||
| 30 | #update=add a field | ||
| 31 | #file=main.zig | ||
| 32 | const S = @This(); | ||
| 33 | x: u8, | ||
| 34 | y: u16 = 200, | ||
| 35 | pub fn main(init: std.process.Init) !void { | ||
| 36 | var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); | ||
| 37 | printFieldCount(&stdout_writer.interface) catch |err| switch (err) { | ||
| 38 | error.WriteFailed => return stdout_writer.err.?, | ||
| 39 | }; | ||
| 40 | printOneField(&stdout_writer.interface) catch |err| switch (err) { | ||
| 41 | error.WriteFailed => return stdout_writer.err.?, | ||
| 42 | }; | ||
| 43 | } | ||
| 44 | fn printFieldCount(w: *Writer) Writer.Error!void { | ||
| 45 | try w.print("{d} ", .{@typeInfo(S).@"struct".fields.len}); | ||
| 46 | } | ||
| 47 | fn printOneField(w: *Writer) Writer.Error!void { | ||
| 48 | const val: S = .{ .x = 100 }; | ||
| 49 | try w.print("{d}\n", .{val.x}); | ||
| 50 | } | ||
| 51 | const std = @import("std"); | ||
| 52 | const Writer = std.Io.Writer; | ||
| 53 | #expect_stdout="2 100\n" | ||
| 54 | |||
| 55 | #update=remove all fields | ||
| 56 | #file=main.zig | ||
| 57 | const S = @This(); | ||
| 58 | pub fn main(init: std.process.Init) !void { | ||
| 59 | var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); | ||
| 60 | printFieldCount(&stdout_writer.interface) catch |err| switch (err) { | ||
| 61 | error.WriteFailed => return stdout_writer.err.?, | ||
| 62 | }; | ||
| 63 | printOneField(&stdout_writer.interface) catch |err| switch (err) { | ||
| 64 | error.WriteFailed => return stdout_writer.err.?, | ||
| 65 | }; | ||
| 66 | } | ||
| 67 | fn printFieldCount(w: *Writer) Writer.Error!void { | ||
| 68 | try w.print("{d} ", .{@typeInfo(S).@"struct".fields.len}); | ||
| 69 | } | ||
| 70 | fn printOneField(w: *Writer) Writer.Error!void { | ||
| 71 | const val: S = .{ .x = 100 }; | ||
| 72 | try w.print("{d}\n", .{val.x}); | ||
| 73 | } | ||
| 74 | const std = @import("std"); | ||
| 75 | const Writer = std.Io.Writer; | ||
| 76 | #expect_error=main.zig:15:24: error: no field named 'x' in struct 'main' | ||
| 77 | #expect_error=main.zig:1:1: note: struct declared here | ||
| 78 | |||
| 79 | #update=remove reference to non-existent field | ||
| 80 | #file=main.zig | ||
| 81 | const S = @This(); | ||
| 82 | pub fn main(init: std.process.Init) !void { | ||
| 83 | var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); | ||
| 84 | printFieldCount(&stdout_writer.interface) catch |err| switch (err) { | ||
| 85 | error.WriteFailed => return stdout_writer.err.?, | ||
| 86 | }; | ||
| 87 | printOneField(&stdout_writer.interface) catch |err| switch (err) { | ||
| 88 | error.WriteFailed => return stdout_writer.err.?, | ||
| 89 | }; | ||
| 90 | } | ||
| 91 | fn printFieldCount(w: *Writer) Writer.Error!void { | ||
| 92 | try w.print("{d} ", .{@typeInfo(S).@"struct".fields.len}); | ||
| 93 | } | ||
| 94 | fn printOneField(w: *Writer) Writer.Error!void { | ||
| 95 | //const val: S = .{ .x = 100 }; | ||
| 96 | //try w.print("{d}\n", .{val.x}); | ||
| 97 | try w.writeAll("<no fields>\n"); | ||
| 98 | } | ||
| 99 | const std = @import("std"); | ||
| 100 | const Writer = std.Io.Writer; | ||
| 101 | #expect_stdout="0 <no fields>\n" | ||