Commit 806470b492
Changed files (2)
src/Compilation.zig
@@ -3935,17 +3935,13 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
for (zcu.failed_imports.items) |failed| {
assert(zcu.alive_files.contains(failed.file_index)); // otherwise it wouldn't have been added
const file = zcu.fileByIndex(failed.file_index);
- const source = file.getSource(zcu) catch |err| {
- try unableToLoadZcuFile(zcu, &bundle, file, err);
- continue;
- };
const tree = file.getTree(zcu) catch |err| {
try unableToLoadZcuFile(zcu, &bundle, file, err);
continue;
};
const start = tree.tokenStart(failed.import_token);
const end = start + tree.tokenSlice(failed.import_token).len;
- const loc = std.zig.findLineColumn(source.bytes, start);
+ const loc = std.zig.findLineColumn(tree.source, start);
try bundle.addRootErrorMessage(.{
.msg = switch (failed.kind) {
.file_outside_module_root => try bundle.addString("import of file outside module path"),
@@ -4338,7 +4334,7 @@ pub fn addModuleErrorMsg(
const err_span = err_src_loc.span(zcu) catch |err| {
return unableToLoadZcuFile(zcu, eb, err_src_loc.file_scope, err);
};
- const err_loc = std.zig.findLineColumn(err_source.bytes, err_span.main);
+ const err_loc = std.zig.findLineColumn(err_source, err_span.main);
var ref_traces: std.ArrayListUnmanaged(ErrorBundle.ReferenceTrace) = .empty;
defer ref_traces.deinit(gpa);
@@ -4434,7 +4430,7 @@ pub fn addModuleErrorMsg(
const span = note_src_loc.span(zcu) catch |err| {
return unableToLoadZcuFile(zcu, eb, note_src_loc.file_scope, err);
};
- const loc = std.zig.findLineColumn(source.bytes, span.main);
+ const loc = std.zig.findLineColumn(source, span.main);
const omit_source_line = loc.eql(err_loc) or (last_note_loc != null and loc.eql(last_note_loc.?));
last_note_loc = loc;
@@ -4489,7 +4485,7 @@ fn addReferenceTraceFrame(
try unableToLoadZcuFile(zcu, eb, src.file_scope, err);
return error.AlreadyReported;
};
- const loc = std.zig.findLineColumn(source.bytes, span.main);
+ const loc = std.zig.findLineColumn(source, span.main);
try ref_traces.append(gpa, .{
.decl_name = try eb.printString("{s}{s}", .{ name, if (inlined) " [inlined]" else "" }),
.src_loc = try eb.addSourceLocation(.{
@@ -4545,8 +4541,13 @@ pub fn unableToLoadZcuFile(
file: *Zcu.File,
err: Zcu.File.GetSourceError,
) Allocator.Error!void {
+ const msg = switch (err) {
+ error.OutOfMemory => |e| return e,
+ error.FileChanged => try eb.addString("file contents changed during update"),
+ else => |e| try eb.printString("unable to load: {t}", .{e}),
+ };
try eb.addRootErrorMessage(.{
- .msg = try eb.printString("unable to load: {t}", .{err}),
+ .msg = msg,
.src_loc = try file.errorBundleWholeFileSrc(zcu, eb),
});
}
src/Zcu.zig
@@ -925,8 +925,11 @@ pub const File = struct {
/// allocated into `gpa`.
path: Compilation.Path,
+ /// Populated only when emitting error messages; see `getSource`.
source: ?[:0]const u8,
+ /// Populated only when emitting error messages; see `getTree`.
tree: ?Ast,
+
zir: ?Zir,
zoir: ?Zoir,
@@ -1033,25 +1036,27 @@ pub const File = struct {
}
}
- pub const Source = struct {
- bytes: [:0]const u8,
- stat: Cache.File.Stat,
- };
-
pub const GetSourceError = error{
OutOfMemory,
- FileTooBig,
- Streaming,
- } || std.fs.File.OpenError || std.fs.File.ReadError;
+ FileChanged,
+ } || std.Io.File.OpenError || std.Io.File.Reader.Error;
- pub fn getSource(file: *File, zcu: *const Zcu) GetSourceError!Source {
+ /// This must only be called in error conditions where `stat` *is* populated. It returns the
+ /// contents of the source file, assuming the stat has not changed since it was originally
+ /// loaded.
+ pub fn getSource(file: *File, zcu: *const Zcu) GetSourceError![:0]const u8 {
const gpa = zcu.gpa;
const io = zcu.comp.io;
- if (file.source) |source| return .{
- .bytes = source,
- .stat = file.stat,
- };
+ if (file.source) |source| return source;
+
+ switch (file.status) {
+ .never_loaded => unreachable, // stat must be populated
+ .retryable_failure => unreachable, // stat must be populated
+ .astgen_failure, .success => {},
+ }
+
+ assert(file.stat.size <= std.math.maxInt(u32)); // `PerThread.updateFile` checks this
var f = f: {
const dir, const sub_path = file.path.openInfo(zcu.comp.dirs);
@@ -1059,40 +1064,43 @@ pub const File = struct {
};
defer f.close();
- const stat = try f.stat();
+ const stat = f.stat() catch |err| switch (err) {
+ error.Streaming => {
+ // Since `file.stat` is populated, this was previously a file stream; since it is
+ // now not a file stream, it must have changed.
+ return error.FileChanged;
+ },
+ else => |e| return e,
+ };
- if (stat.size > std.math.maxInt(u32))
- return error.FileTooBig;
+ if (stat.inode != file.stat.inode or
+ stat.size != file.stat.size or
+ stat.mtime.nanoseconds != file.stat.mtime.nanoseconds)
+ {
+ return error.FileChanged;
+ }
- const source = try gpa.allocSentinel(u8, @intCast(stat.size), 0);
+ const source = try gpa.allocSentinel(u8, @intCast(file.stat.size), 0);
errdefer gpa.free(source);
var file_reader = f.reader(io, &.{});
file_reader.size = stat.size;
file_reader.interface.readSliceAll(source) catch return file_reader.err.?;
- // Here we do not modify stat fields because this function is the one
- // used for error reporting. We need to keep the stat fields stale so that
- // updateFile can know to regenerate ZIR.
-
file.source = source;
errdefer comptime unreachable; // don't error after populating `source`
- return .{
- .bytes = source,
- .stat = .{
- .size = stat.size,
- .inode = stat.inode,
- .mtime = stat.mtime,
- },
- };
+ return source;
}
+ /// This must only be called in error conditions where `stat` *is* populated. It returns the
+ /// parsed AST of the source file, assuming the stat has not changed since it was originally
+ /// loaded.
pub fn getTree(file: *File, zcu: *const Zcu) GetSourceError!*const Ast {
if (file.tree) |*tree| return tree;
const source = try file.getSource(zcu);
- file.tree = try .parse(zcu.gpa, source.bytes, file.getMode());
+ file.tree = try .parse(zcu.gpa, source, file.getMode());
return &file.tree.?;
}