refactor(tvix/eval): use internal SourceCode field in error printers

Makes use of the SourceCode field now being stored directly in
errors (see parent CL). With this change, the default `Display`
implementation can now format errors correctly, and there is no need
to keep a `SourceCode` around just for error formatting.

Updates dependent crates (CLI, serde, tvixbolt) to use this correctly.

Change-Id: Iddc5d7a6b4bab391f30a999e4c68aca34304c059
Reviewed-on: https://cl.tvl.fyi/c/depot/+/10987
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
This commit is contained in:
Vincent Ambo 2024-02-20 15:38:33 +07:00 committed by tazjin
parent 3c87687798
commit 94f582341e
5 changed files with 22 additions and 33 deletions

View file

@ -323,12 +323,7 @@ fn eval(model: &Model) -> Output {
if !result.errors.is_empty() { if !result.errors.is_empty() {
for error in &result.errors { for error in &result.errors {
writeln!( writeln!(&mut out.errors, "{}\n", error.fancy_format_str().trim(),).unwrap();
&mut out.errors,
"{}\n",
error.fancy_format_str(&source).trim(),
)
.unwrap();
} }
return out; return out;

View file

@ -159,7 +159,7 @@ fn interpret(code: &str, path: Option<PathBuf>, args: &Args, explain: bool) -> b
} }
for error in &result.errors { for error in &result.errors {
error.fancy_format_stderr(&source_map); error.fancy_format_stderr();
} }
if !args.no_warnings { if !args.no_warnings {
@ -207,7 +207,7 @@ fn lint(code: &str, path: Option<PathBuf>, args: &Args) -> bool {
} }
for error in &result.errors { for error in &result.errors {
error.fancy_format_stderr(&source_map); error.fancy_format_stderr();
} }
for warning in &result.warnings { for warning in &result.warnings {

View file

@ -514,7 +514,7 @@ to a missing value in the attribute set(s) included via `with`."#,
impl Display for Error { impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.kind) write!(f, "{}", self.fancy_format_str())
} }
} }
@ -739,17 +739,16 @@ fn spans_for_parse_errors(file: &File, errors: &[rnix::parser::ParseError]) -> V
} }
impl Error { impl Error {
pub fn fancy_format_str(&self, source: &SourceCode) -> String { pub fn fancy_format_str(&self) -> String {
let mut out = vec![]; let mut out = vec![];
Emitter::vec(&mut out, Some(&*source.codemap())).emit(&self.diagnostics(source)); Emitter::vec(&mut out, Some(&*self.source.codemap())).emit(&self.diagnostics());
String::from_utf8_lossy(&out).to_string() String::from_utf8_lossy(&out).to_string()
} }
/// Render a fancy, human-readable output of this error and print /// Render a fancy, human-readable output of this error and print
/// it to stderr. /// it to stderr.
pub fn fancy_format_stderr(&self, source: &SourceCode) { pub fn fancy_format_stderr(&self) {
Emitter::stderr(ColorConfig::Auto, Some(&*source.codemap())) Emitter::stderr(ColorConfig::Auto, Some(&*self.source.codemap())).emit(&self.diagnostics());
.emit(&self.diagnostics(source));
} }
/// Create the optional span label displayed as an annotation on /// Create the optional span label displayed as an annotation on
@ -863,14 +862,14 @@ impl Error {
} }
} }
fn spans(&self, source: &SourceCode) -> Vec<SpanLabel> { fn spans(&self) -> Vec<SpanLabel> {
let mut spans = match &self.kind { let mut spans = match &self.kind {
ErrorKind::ImportParseError { errors, file, .. } => { ErrorKind::ImportParseError { errors, file, .. } => {
spans_for_parse_errors(file, errors) spans_for_parse_errors(file, errors)
} }
ErrorKind::ParseErrors(errors) => { ErrorKind::ParseErrors(errors) => {
let file = source.get_file(self.span); let file = self.source.get_file(self.span);
spans_for_parse_errors(&file, errors) spans_for_parse_errors(&file, errors)
} }
@ -949,22 +948,22 @@ impl Error {
} }
/// Create the primary diagnostic for a given error. /// Create the primary diagnostic for a given error.
fn diagnostic(&self, source: &SourceCode) -> Diagnostic { fn diagnostic(&self) -> Diagnostic {
Diagnostic { Diagnostic {
level: Level::Error, level: Level::Error,
message: self.to_string(), message: self.to_string(),
spans: self.spans(source), spans: self.spans(),
code: Some(self.code().into()), code: Some(self.code().into()),
} }
} }
/// Return the primary diagnostic and all further associated diagnostics (if /// Return the primary diagnostic and all further associated diagnostics (if
/// any) of an error. /// any) of an error.
fn diagnostics(&self, source: &SourceCode) -> Vec<Diagnostic> { fn diagnostics(&self) -> Vec<Diagnostic> {
match &self.kind { match &self.kind {
ErrorKind::ImportCompilerError { errors, .. } => { ErrorKind::ImportCompilerError { errors, .. } => {
let mut out = vec![self.diagnostic(source)]; let mut out = vec![self.diagnostic()];
out.extend(errors.iter().map(|e| e.diagnostic(source))); out.extend(errors.iter().map(|e| e.diagnostic()));
out out
} }
@ -991,7 +990,7 @@ impl Error {
let mut this_span = self.span; let mut this_span = self.span;
// Diagnostic spans for *this* error. // Diagnostic spans for *this* error.
let mut this_spans = self.spans(source); let mut this_spans = self.spans();
loop { loop {
if is_new_span( if is_new_span(
@ -1008,7 +1007,7 @@ impl Error {
this_message = next.to_string(); this_message = next.to_string();
this_span = next.span; this_span = next.span;
this_spans = next.spans(source); this_spans = next.spans();
match next.kind { match next.kind {
ErrorKind::NativeError { err: inner, .. } ErrorKind::NativeError { err: inner, .. }
@ -1017,7 +1016,7 @@ impl Error {
continue; continue;
} }
_ => { _ => {
diagnostics.extend(next.diagnostics(source)); diagnostics.extend(next.diagnostics());
break; break;
} }
} }
@ -1026,7 +1025,7 @@ impl Error {
diagnostics diagnostics
} }
_ => vec![self.diagnostic(source)], _ => vec![self.diagnostic()],
} }
} }
} }

View file

@ -51,13 +51,11 @@ where
config(&mut eval); config(&mut eval);
eval.strict = true; eval.strict = true;
let source = eval.source_map();
let result = eval.evaluate(src, None); let result = eval.evaluate(src, None);
if !result.errors.is_empty() { if !result.errors.is_empty() {
return Err(Error::NixErrors { return Err(Error::NixErrors {
errors: result.errors, errors: result.errors,
source,
}); });
} }

View file

@ -27,10 +27,7 @@ pub enum Error {
/// Evaluation of the supplied Nix code failed while computing the /// Evaluation of the supplied Nix code failed while computing the
/// value for deserialisation. /// value for deserialisation.
NixErrors { NixErrors { errors: Vec<tvix_eval::Error> },
errors: Vec<tvix_eval::Error>,
source: tvix_eval::SourceCode,
},
/// Could not determine an externally tagged enum representation. /// Could not determine an externally tagged enum representation.
AmbiguousEnum, AmbiguousEnum,
@ -56,7 +53,7 @@ impl Display for Error {
write!(f, "expected type {}, but got Nix type {}", expected, got) write!(f, "expected type {}, but got Nix type {}", expected, got)
} }
Error::NixErrors { errors, source } => { Error::NixErrors { errors } => {
writeln!( writeln!(
f, f,
"{} occured during Nix evaluation: ", "{} occured during Nix evaluation: ",
@ -64,7 +61,7 @@ impl Display for Error {
)?; )?;
for err in errors { for err in errors {
writeln!(f, "{}", err.fancy_format_str(source))?; writeln!(f, "{}", err.fancy_format_str())?;
} }
Ok(()) Ok(())