diff --git a/src/cli/main.zig b/src/cli/main.zig index 2bdc5ea7db..d60b55f549 100644 --- a/src/cli/main.zig +++ b/src/cli/main.zig @@ -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(); diff --git a/src/compile/compile_package.zig b/src/compile/compile_package.zig index 243f19b87f..1f56fd0125 100644 --- a/src/compile/compile_package.zig +++ b/src/compile/compile_package.zig @@ -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