From aba8ec95cf16b99ca79ac3eefd44cd3f5a81660b Mon Sep 17 00:00:00 2001 From: Bernardo Uriarte Date: Sun, 31 Jul 2022 12:16:25 +0200 Subject: [PATCH] add source to diagnostics --- components/dada-execute/src/step.rs | 16 +++-- components/dada-execute/src/step/access.rs | 6 +- components/dada-execute/src/step/address.rs | 1 + components/dada-execute/src/step/apply_op.rs | 11 ++-- .../dada-execute/src/step/apply_unary.rs | 3 +- .../dada-execute/src/step/await_thunk.rs | 8 ++- components/dada-execute/src/step/call.rs | 3 + components/dada-execute/src/step/intrinsic.rs | 2 +- components/dada-execute/src/step/traversal.rs | 13 ++-- components/dada-ir/src/diagnostic.rs | 63 +++++++++++++++---- components/dada-lex/src/lex.rs | 1 + components/dada-parse/src/parser.rs | 7 ++- components/dada-parse/src/parser/items.rs | 3 +- .../dada-validate/src/validate/name_lookup.rs | 1 + .../dada-validate/src/validate/validator.rs | 35 ++++++++--- .../src/validate/validator/string_literals.rs | 8 ++- 16 files changed, 134 insertions(+), 47 deletions(-) diff --git a/components/dada-execute/src/step.rs b/components/dada-execute/src/step.rs index 694e78d8..1608dbd5 100644 --- a/components/dada-execute/src/step.rs +++ b/components/dada-execute/src/step.rs @@ -346,11 +346,11 @@ impl<'me> Stepper<'me> { } TerminatorData::Error => { let span = self.span_from_bir(terminator); - Err(error!(span, "compilation error encountered 😢").eyre(self.db)) + Err(error!(Execute, span, "compilation error encountered 😢").eyre(self.db)) } TerminatorData::Panic => { let span = self.span_from_bir(terminator); - Err(error!(span, "panic! omg! 😱").eyre(self.db)) + Err(error!(Execute, span, "panic! omg! 😱").eyre(self.db)) } } } @@ -473,7 +473,7 @@ impl<'me> Stepper<'me> { } bir::ExprData::Error => { let span = self.span_from_bir(expr); - Err(error!(span, "compilation error").eyre(self.db)) + Err(error!(Execute, span, "compilation error").eyre(self.db)) } } } @@ -484,13 +484,21 @@ impl<'me> Stepper<'me> { object: &ObjectData, what: &str, ) -> eyre::Report { - error!(span, "expected {}, found {}", what, object.kind_str(db)).eyre(db) + error!( + Execute, + span, + "expected {}, found {}", + what, + object.kind_str(db) + ) + .eyre(db) } fn no_such_field(db: &dyn crate::Db, span: FileSpan, class: Class, name: Word) -> eyre::Report { let class_name = class.name(db).as_str(db); let class_span = class.name(db).span(db); error!( + Execute, span, "the class `{}` has no field named `{}`", class_name, diff --git a/components/dada-execute/src/step/access.rs b/components/dada-execute/src/step/access.rs index bc1b25cb..b20f5ee7 100644 --- a/components/dada-execute/src/step/access.rs +++ b/components/dada-execute/src/step/access.rs @@ -76,12 +76,14 @@ impl Stepper<'_> { // since we need to distinguish between an atomic location in a // shared object vs a shared object in an (exclusive) atomic location. let span = self.machine.pc().span(self.db); - return Err(error!(span, "atomic writes not implemented yet").eyre(self.db)); + return Err( + error!(Execute, span, "atomic writes not implemented yet").eyre(self.db) + ); } (Joint::Yes, Atomic::No) => { let span = self.machine.pc().span(self.db); - return Err(error!(span, "cannot write to shared fields").eyre(self.db)); + return Err(error!(Execute, span, "cannot write to shared fields").eyre(self.db)); } (Joint::No, Atomic::Yes) | (Joint::No, Atomic::No) => { diff --git a/components/dada-execute/src/step/address.rs b/components/dada-execute/src/step/address.rs index 440dae0a..d5977012 100644 --- a/components/dada-execute/src/step/address.rs +++ b/components/dada-execute/src/step/address.rs @@ -43,6 +43,7 @@ impl Stepper<'_> { Address::Local(lv) => self.machine[lv] = value, Address::Constant(_) => { return Err(error!( + Execute, self.machine.pc().span(self.db), "cannot store into a constant" ) diff --git a/components/dada-execute/src/step/apply_op.rs b/components/dada-execute/src/step/apply_op.rs index d597cfbf..4adb2897 100644 --- a/components/dada-execute/src/step/apply_op.rs +++ b/components/dada-execute/src/step/apply_op.rs @@ -22,6 +22,7 @@ impl Stepper<'_> { let op_error = || { let span = self.span_from_bir(expr); Err(error!( + Execute, span, "cannot apply operator {} to {} and {}", op, @@ -32,11 +33,11 @@ impl Stepper<'_> { }; let div_zero_error = || { let span = self.span_from_bir(expr); - Err(error!(span, "divide by zero").eyre(self.db)) + Err(error!(Execute, span, "divide by zero").eyre(self.db)) }; let overflow_error = || { let span = self.span_from_bir(expr); - Err(error!(span, "overflow").eyre(self.db)) + Err(error!(Execute, span, "overflow").eyre(self.db)) }; match (&self.machine[lhs], &self.machine[rhs]) { (&ObjectData::Bool(lhs), &ObjectData::Bool(rhs)) => match op { @@ -149,11 +150,11 @@ impl Stepper<'_> { ) -> eyre::Result { let div_zero_error = || { let span = self.span_from_bir(expr); - Err(error!(span, "divide by zero").eyre(self.db)) + Err(error!(Execute, span, "divide by zero").eyre(self.db)) }; let overflow_error = || { let span = self.span_from_bir(expr); - Err(error!(span, "overflow").eyre(self.db)) + Err(error!(Execute, span, "overflow").eyre(self.db)) }; match op { Op::EqualEqual => Ok(self.machine.our_value(lhs == rhs)), @@ -178,7 +179,7 @@ impl Stepper<'_> { div_zero_error() } else { let span = self.span_from_bir(expr); - Err(error!(span, "signed division overflow").eyre(self.db)) + Err(error!(Execute, span, "signed division overflow").eyre(self.db)) } } }, diff --git a/components/dada-execute/src/step/apply_unary.rs b/components/dada-execute/src/step/apply_unary.rs index dfd4da54..b18791d8 100644 --- a/components/dada-execute/src/step/apply_unary.rs +++ b/components/dada-execute/src/step/apply_unary.rs @@ -21,6 +21,7 @@ impl Stepper<'_> { let op_error = || { let span = self.span_from_bir(expr); Err(error!( + Execute, span, "cannot apply operator {} to {}", op, @@ -34,7 +35,7 @@ impl Stepper<'_> { Ok(rhs) => Ok(self.machine.our_value(-rhs)), Err(_) => { let span = self.span_from_bir(expr); - Err(error!(span, "overflow").eyre(self.db)) + Err(error!(Execute, span, "overflow").eyre(self.db)) } }, _ => op_error(), diff --git a/components/dada-execute/src/step/await_thunk.rs b/components/dada-execute/src/step/await_thunk.rs index d161eb20..b52fef35 100644 --- a/components/dada-execute/src/step/await_thunk.rs +++ b/components/dada-execute/src/step/await_thunk.rs @@ -68,8 +68,10 @@ impl Stepper<'_> { (Joint::No, Leased::No) => return Ok(()), }; let span = self.span_from_bir(thunk_place); - Err(error!(span, "awaiting something requires full ownership") - .primary_label(primary_label) - .eyre(self.db)) + Err( + error!(Execute, span, "awaiting something requires full ownership") + .primary_label(primary_label) + .eyre(self.db), + ) } } diff --git a/components/dada-execute/src/step/call.rs b/components/dada-execute/src/step/call.rs index 3e592016..2f4551b2 100644 --- a/components/dada-execute/src/step/call.rs +++ b/components/dada-execute/src/step/call.rs @@ -80,6 +80,7 @@ impl Stepper<'_> { data => { let span = self.span_from_bir(callee); Err(error!( + Execute, span, "expected something callable, found {}", data.kind_str(self.db) @@ -114,6 +115,7 @@ impl Stepper<'_> { if let Some(actual_word) = actual_label.word(db) { if expected_name != actual_word { return Err(error!( + Execute, actual_label.span(db), "expected to find an argument named `{}`, but found the name `{}`", expected_name.as_str(db), @@ -126,6 +128,7 @@ impl Stepper<'_> { if actual_labels.len() != expected_names.len() { return Err(error!( + Execute, self.span_from_bir(call_terminator), "expected to find {} arguments, but found {}", expected_names.len(), diff --git a/components/dada-execute/src/step/intrinsic.rs b/components/dada-execute/src/step/intrinsic.rs index b89a704d..185600d3 100644 --- a/components/dada-execute/src/step/intrinsic.rs +++ b/components/dada-execute/src/step/intrinsic.rs @@ -72,7 +72,7 @@ impl Stepper<'_> { .await .with_context(|| { let span_now = self.machine.pc().span(self.db); - error!(span_now, "error printing `{:?}`", message_str).eyre(self.db) + error!(Execute, span_now, "error printing `{:?}`", message_str).eyre(self.db) })?; Ok(self.machine.our_value(())) diff --git a/components/dada-execute/src/step/traversal.rs b/components/dada-execute/src/step/traversal.rs index 144f7035..e45cb164 100644 --- a/components/dada-execute/src/step/traversal.rs +++ b/components/dada-execute/src/step/traversal.rs @@ -326,7 +326,7 @@ impl Stepper<'_> { expired_at: Option, ) -> eyre::Report { match expired_at { - None => error!(place_span, "accessing uninitialized memory").eyre(self.db), + None => error!(Execute, place_span, "accessing uninitialized memory").eyre(self.db), Some(expired_at) => { let expired_at_span = expired_at.span(self.db); @@ -336,10 +336,13 @@ impl Stepper<'_> { "lease was cancelled here" }; - error!(place_span, "your lease to this object was cancelled") - .primary_label("cancelled lease used here") - .secondary_label(expired_at_span, secondary_label) - .eyre(self.db) + error!( + Execute, + place_span, "your lease to this object was cancelled" + ) + .primary_label("cancelled lease used here") + .secondary_label(expired_at_span, secondary_label) + .eyre(self.db) } } } diff --git a/components/dada-ir/src/diagnostic.rs b/components/dada-ir/src/diagnostic.rs index db2e9f7b..a12b78fe 100644 --- a/components/dada-ir/src/diagnostic.rs +++ b/components/dada-ir/src/diagnostic.rs @@ -13,6 +13,7 @@ pub struct ErrorReported; #[derive(Clone, PartialEq, Eq, Hash, Debug)] #[non_exhaustive] pub struct Diagnostic { + pub source: Source, pub severity: Severity, pub span: FileSpan, pub message: String, @@ -20,6 +21,14 @@ pub struct Diagnostic { pub children: Vec, } +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum Source { + Lex, + Parse, + Validate, + Execute, +} + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum Severity { Help, @@ -41,48 +50,73 @@ pub struct Diagnostics(Diagnostic); /// Convenience macro for avoiding `format!` #[macro_export] macro_rules! diag { - ($severity:expr, $span:expr, $($message:tt)*) => { - $crate::diagnostic::Diagnostic::builder($severity, $span, format!($($message)*)) + ($source:ident, $severity:ident, $span:expr, $($message:tt)*) => { + $crate::diagnostic::Diagnostic::builder( + $crate::diagnostic::Source::$source, + $crate::diagnostic::Severity::$severity, + $span, format!($($message)*) + ) } } /// Convenience macro for avoiding `format!` #[macro_export] macro_rules! error { - ($span:expr, $($message:tt)*) => { - $crate::diagnostic::Diagnostic::builder($crate::diagnostic::Severity::Error, $span, format!($($message)*)) + ($source:ident, $span:expr, $($message:tt)*) => { + $crate::diagnostic::Diagnostic::builder( + $crate::diagnostic::Source::$source, + $crate::diagnostic::Severity::Error, + $span, format!($($message)*) + ) } } /// Convenience macro for avoiding `format!` #[macro_export] macro_rules! warning { - ($span:expr, $($message:tt)*) => { - $crate::diagnostic::Diagnostic::builder($crate::diagnostic::Severity::Warning, $span, format!($($message)*)) + ($source:ident, $span:expr, $($message:tt)*) => { + $crate::diagnostic::Diagnostic::builder( + $crate::diagnostic::Source::$source, + $crate::diagnostic::Severity::Warning, + $span, format!($($message)*) + ) } } /// Convenience macro for avoiding `format!` #[macro_export] macro_rules! note { - ($span:expr, $($message:tt)*) => { - $crate::diagnostic::Diagnostic::builder($crate::diagnostic::Severity::Note, $span, format!($($message)*)) + ($source:ident, $span:expr, $($message:tt)*) => { + $crate::diagnostic::Diagnostic::builder( + $crate::diagnostic::Source::$source, + $crate::diagnostic::Severity::Note, + $span, format!($($message)*) + ) } } /// Convenience macro for avoiding `format!` #[macro_export] macro_rules! help { - ($span:expr, $($message:tt)*) => { - $crate::diagnostic::Diagnostic::builder($crate::diagnostic::Severity::Help, $span, format!($($message)*)) + ($source:ident, $span:expr, $($message:tt)*) => { + $crate::diagnostic::Diagnostic::builder( + $crate::diagnostic::Source::$source, + $crate::diagnostic::Severity::Help, + $span, format!($($message)*) + ) } } impl Diagnostic { /// Create a new diagnostic builder with the given "main message" at the /// given span. - pub fn builder(severity: Severity, span: FileSpan, message: String) -> DiagnosticBuilder { - DiagnosticBuilder::new(severity, span, message) + pub fn builder( + source: Source, + severity: Severity, + span: FileSpan, + message: String, + ) -> DiagnosticBuilder { + DiagnosticBuilder::new(source, severity, span, message) } /// Emit the diagnostic to the [`Diagnostics`] accumulator. @@ -107,6 +141,7 @@ impl Label { #[must_use] pub struct DiagnosticBuilder { + source: Source, severity: Severity, span: FileSpan, message: String, @@ -122,8 +157,9 @@ pub struct DiagnosticBuilder { } impl DiagnosticBuilder { - fn new(severity: Severity, span: FileSpan, message: impl ToString) -> Self { + fn new(source: Source, severity: Severity, span: FileSpan, message: impl ToString) -> Self { Self { + source, severity, span, message: message.to_string(), @@ -186,6 +222,7 @@ impl DiagnosticBuilder { } Diagnostic { + source: self.source, severity: self.severity, span: self.span, message: self.message, diff --git a/components/dada-lex/src/lex.rs b/components/dada-lex/src/lex.rs index 53e7edf6..e523c1ca 100644 --- a/components/dada-lex/src/lex.rs +++ b/components/dada-lex/src/lex.rs @@ -217,6 +217,7 @@ where .unwrap_or(self.file_len), ); dada_ir::error!( + Lex, Span { start: ch_offset, end, diff --git a/components/dada-parse/src/parser.rs b/components/dada-parse/src/parser.rs index d73f3a71..b1317f4b 100644 --- a/components/dada-parse/src/parser.rs +++ b/components/dada-parse/src/parser.rs @@ -198,7 +198,12 @@ impl<'me> Parser<'me> { } fn error(&self, span: Span, message: impl ToString) -> DiagnosticBuilder { - dada_ir::error!(span.in_file(self.input_file), "{}", message.to_string()) + dada_ir::error!( + Parse, + span.in_file(self.input_file), + "{}", + message.to_string() + ) } } diff --git a/components/dada-parse/src/parser/items.rs b/components/dada-parse/src/parser/items.rs index 60db98bc..20c1fd99 100644 --- a/components/dada-parse/src/parser/items.rs +++ b/components/dada-parse/src/parser/items.rs @@ -32,7 +32,8 @@ impl<'db> Parser<'db> { } else { let span = self.tokens.last_span(); self.tokens.consume(); - dada_ir::error!(span.in_file(self.input_file), "unexpected token").emit(self.db); + dada_ir::error!(Parse, span.in_file(self.input_file), "unexpected token") + .emit(self.db); } } diff --git a/components/dada-validate/src/validate/name_lookup.rs b/components/dada-validate/src/validate/name_lookup.rs index c2d48615..d7aa404c 100644 --- a/components/dada-validate/src/validate/name_lookup.rs +++ b/components/dada-validate/src/validate/name_lookup.rs @@ -119,6 +119,7 @@ impl RootDefinitions { if let Some(&other_definition) = names.get(&name) { let other_item: Item = other_definition.try_into().unwrap(); dada_ir::error!( + Validate, item.name_span(db), "already have a {} named `{}`", other_item.kind_str(), diff --git a/components/dada-validate/src/validate/validator.rs b/components/dada-validate/src/validate/validator.rs index e754ff9f..c6a4df4c 100644 --- a/components/dada-validate/src/validate/validator.rs +++ b/components/dada-validate/src/validate/validator.rs @@ -148,6 +148,7 @@ impl<'me> Validator<'me> { if let validated::ExprData::Seq(exprs) = validated_expr.data(self.tables) { if exprs.is_empty() { dada_ir::error!( + Validate, self.function.return_type(self.db).span(self.db), "function body cannot be empty", ) @@ -208,7 +209,7 @@ impl<'me> Validator<'me> { let raw_str = w.as_str(self.db); let without_underscore: String = raw_str.chars().filter(|&c| c != '_').collect(); let parse_error = |this: &mut Validator, e| { - dada_ir::error!(this.span(expr), "{}", e,).emit(this.db); + dada_ir::error!(Validate, this.span(expr), "{}", e,).emit(this.db); this.add(validated::ExprData::Error, expr) }; match suffix { @@ -267,6 +268,7 @@ impl<'me> Validator<'me> { Ok(v) => self.add(validated::ExprData::FloatLiteral(eq_float::F64(v)), expr), Err(e) => { dada_ir::error!( + Validate, self.span(expr), "`{}.{}` is not a valid float: {}", w_int.as_str(self.db), @@ -296,6 +298,7 @@ impl<'me> Validator<'me> { match self.effect { Effect::Atomic => { dada_ir::error!( + Validate, await_span, "await is not permitted inside atomic sections", ) @@ -305,6 +308,7 @@ impl<'me> Validator<'me> { } Effect::Default => { dada_ir::error!( + Validate, await_span, "await is not permitted outside of async functions", ) @@ -331,7 +335,7 @@ impl<'me> Validator<'me> { if name.word(self.db).is_some() { name_required = true; } else if name_required { - dada_ir::error!(name.span(self.db), "parameter name required",) + dada_ir::error!(Validate, name.span(self.db), "parameter name required",) .primary_label("parameter name required here") .emit(self.db); } @@ -519,9 +523,13 @@ impl<'me> Validator<'me> { let validated_data = match self.loop_stack.last() { Some(loop_expr) => validated::ExprData::Continue(*loop_expr), None => { - dada_ir::error!(self.span(expr), "cannot `continue` outside of a loop") - .primary_label("`continue` outside of a loop here") - .emit(self.db); + dada_ir::error!( + Validate, + self.span(expr), + "cannot `continue` outside of a loop" + ) + .primary_label("`continue` outside of a loop here") + .emit(self.db); validated::ExprData::Error } }; @@ -540,9 +548,13 @@ impl<'me> Validator<'me> { with_value: validated_expr, }, None => { - dada_ir::error!(self.span(expr), "cannot `break` outside of a loop") - .primary_label("`break` outside of a loop here") - .emit(self.db); + dada_ir::error!( + Validate, + self.span(expr), + "cannot `break` outside of a loop" + ) + .primary_label("`break` outside of a loop here") + .emit(self.db); validated::ExprData::Error } }; @@ -551,7 +563,7 @@ impl<'me> Validator<'me> { syntax::ExprData::Return(with_value) => { match (self.function.return_type(self.db).kind(self.db), with_value) { (ReturnTypeKind::Value, None) => { - dada_ir::error!(self.span(expr), "return requires an expression") + dada_ir::error!(Validate, self.span(expr), "return requires an expression") .primary_label( "cannot just have `return` without an expression afterwards", ) @@ -563,6 +575,7 @@ impl<'me> Validator<'me> { } (ReturnTypeKind::Unit, Some(return_expr)) => { dada_ir::error!( + Validate, self.span(*return_expr), "cannot return a value in this function" ) @@ -701,6 +714,7 @@ impl<'me> Validator<'me> { | Some(definition @ Definition::Class(_)) | Some(definition @ Definition::Intrinsic(_)) => { let ErrorReported = dada_ir::error!( + Validate, self.span(expr), "you can only assign to local variables or fields, not {} like `{}`", definition.plural_description(), @@ -712,6 +726,7 @@ impl<'me> Validator<'me> { None => { let ErrorReported = dada_ir::error!( + Validate, self.span(expr), "can't find anything named `{}`", name.as_str(self.db) @@ -728,6 +743,7 @@ impl<'me> Validator<'me> { _ => { let _ = self.validate_expr(expr); let ErrorReported = dada_ir::error!( + Validate, self.span(expr), "you can only assign to local variables and fields, not arbitrary expressions", ) @@ -827,6 +843,7 @@ impl<'me> Validator<'me> { } None => { let ErrorReported = dada_ir::error!( + Validate, self.span(expr), "can't find anything named `{}`", name.as_str(self.db) diff --git a/components/dada-validate/src/validate/validator/string_literals.rs b/components/dada-validate/src/validate/validator/string_literals.rs index 9c3170c3..7c85c70b 100644 --- a/components/dada-validate/src/validate/validator/string_literals.rs +++ b/components/dada-validate/src/validate/validator/string_literals.rs @@ -38,8 +38,12 @@ impl Validator<'_> { // literal, but that's a *touch* tricky to do since `s` may be some // stripped subset. We'd either have to track original span info for `s` // or else recompute it. - dada_ir::error!(self.span(expr), "unrecognized escape `\\{c}`",) - .emit(self.db); + dada_ir::error!( + Validate, + self.span(expr), + "unrecognized escape `\\{c}`", + ) + .emit(self.db); } } }