Improve file not found error reporting

This commit is contained in:
Richard Feldman 2025-10-24 13:28:12 -04:00
parent 3fa79da27c
commit bc04add299
No known key found for this signature in database
2 changed files with 91 additions and 2 deletions

View file

@ -2798,6 +2798,35 @@ fn checkFileWithBuildEnvPreserved(
// Build the file (works for both app and module files)
build_env.build(filepath) catch |err| {
// Even on error, try to drain and print any reports that were collected
const drained = build_env.drainReports() catch &[_]BuildEnv.DrainedModuleReports{};
defer build_env.gpa.free(drained);
// Print any error reports to stderr before failing
const stderr = std.fs.File.stderr();
const num_reports = blk: {
var count: usize = 0;
for (drained) |mod| count += mod.reports.len;
break :blk count;
};
if (num_reports > 0) {
_ = stderr.write("DEBUG: Found ") catch {};
var buf: [32]u8 = undefined;
const count_str = std.fmt.bufPrint(&buf, "{d}", .{num_reports}) catch "?";
_ = stderr.write(count_str) catch {};
_ = stderr.write(" reports\n") catch {};
for (drained) |mod| {
for (mod.reports) |report| {
_ = stderr.write(report.title) catch {};
_ = stderr.write("\n") catch {};
}
}
} else {
_ = stderr.write("DEBUG: No reports found\n") catch {};
}
return err;
};
@ -2894,7 +2923,24 @@ fn checkFileWithBuildEnv(
}
// Build the file (works for both app and module files)
try build_env.build(filepath);
build_env.build(filepath) catch {
// Even on error, drain reports to show what went wrong
const drained = build_env.drainReports() catch &[_]BuildEnv.DrainedModuleReports{};
defer build_env.gpa.free(drained);
// Convert BuildEnv drained reports to our format
var reports = try build_env.gpa.alloc(DrainedReport, drained.len);
for (drained, 0..) |mod, i| {
reports[i] = .{
.file_path = try build_env.gpa.dupe(u8, mod.abs_path),
.reports = try build_env.gpa.dupe(reporting.Report, mod.reports),
};
}
return CheckResult{
.reports = reports,
};
};
// Drain all reports
const drained = try build_env.drainReports();

View file

@ -534,7 +534,50 @@ pub const PackageEnv = struct {
fn doParse(self: *PackageEnv, module_id: ModuleId) !void {
// Load source and init ModuleEnv
var st = &self.modules.items[module_id];
const src = try std.fs.cwd().readFileAlloc(self.gpa, st.path, std.math.maxInt(usize));
const src = std.fs.cwd().readFileAlloc(self.gpa, st.path, std.math.maxInt(usize)) catch |read_err| {
// If the file wasn't found, create a proper diagnostic report
if (read_err == error.FileNotFound) {
// Create a diagnostic on the importing module(s)
for (st.dependents.items) |importer_id| {
const importer = &self.modules.items[importer_id];
var rep = Report.init(self.gpa, "Module not found", .runtime_error);
const msg1 = try std.fmt.allocPrint(self.gpa,
"Could not find module '{s}' at the following path:", .{st.name});
_ = try rep.addOwnedString(msg1);
try rep.addErrorMessage(msg1);
try rep.document.addLineBreak();
const path_msg = try rep.addOwnedString(st.path);
try rep.document.addText(" ");
try rep.document.addAnnotated(path_msg, .emphasized);
try rep.document.addLineBreak();
try rep.document.addLineBreak();
const hint = try rep.addOwnedString(
"This module was imported but the file does not exist. " ++
"If this is a builtin module like Str, Bool, or Result, " ++
"they are automatically available and should not be explicitly imported.");
try rep.document.addText(hint);
// Emit the report immediately so it gets displayed
self.sink.emitFn(self.sink.ctx, importer.name, rep);
}
// If no importers (shouldn't happen), add report to this module
if (st.dependents.items.len == 0) {
var rep = Report.init(self.gpa, "Module not found", .runtime_error);
const msg = try std.fmt.allocPrint(self.gpa,
"Could not find module file at: {s}", .{st.path});
_ = try rep.addOwnedString(msg);
try rep.addErrorMessage(msg);
// Emit the report immediately so it gets displayed
self.sink.emitFn(self.sink.ctx, st.name, rep);
}
}
return read_err;
};
// line starts for diagnostics and consistent positions