From 22e95de48d0f1a115282a0ab68124ef2b60648df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabrielle=20Guimar=C3=A3es=20de=20Oliveira?= Date: Wed, 29 May 2024 00:50:34 -0300 Subject: [PATCH] feat(sol-diagnostic): add bail and other eyre functions --- sol-diagnostic/src/lib.rs | 163 ++++++++++++++++++++++++++++++++- sol-thir-lowering/src/infer.rs | 3 +- 2 files changed, 164 insertions(+), 2 deletions(-) diff --git a/sol-diagnostic/src/lib.rs b/sol-diagnostic/src/lib.rs index c684dfc..3a85818 100644 --- a/sol-diagnostic/src/lib.rs +++ b/sol-diagnostic/src/lib.rs @@ -55,7 +55,7 @@ impl IntoSolDiagnostic for Result { } #[derive(Clone, Debug)] -pub struct Diagnostic(Arc); +pub struct Diagnostic(pub Arc); impl Eq for Diagnostic {} @@ -147,3 +147,164 @@ impl miette::SourceCode for TextSource { ))) } } + +/// Return early with an error. +/// +/// This macro is equivalent to `return Err(From::from($err))`. +/// +/// # Example +/// +/// ``` +/// # use sol_eyre::{bail, Result}; +/// # +/// # fn has_permission(user: usize, resource: usize) -> bool { +/// # true +/// # } +/// # +/// # fn main() -> Result<()> { +/// # let user = 0; +/// # let resource = 0; +/// # +/// if !has_permission(user, resource) { +/// bail!("permission denied for accessing {}", resource); +/// } +/// # Ok(()) +/// # } +/// ``` +/// +/// ``` +/// # use sol_diagnostic::{bail, Result}; +/// # use thiserror::Error; +/// # +/// # const MAX_DEPTH: usize = 1; +/// # +/// #[derive(Error, Debug)] +/// enum ScienceError { +/// #[error("recursion limit exceeded")] +/// RecursionLimitExceeded, +/// # #[error("...")] +/// # More = (stringify! { +/// ... +/// # }, 1).1, +/// } +/// +/// # fn main() -> Result<()> { +/// # let depth = 0; +/// # let err: &'static dyn std::error::Error = &ScienceError::RecursionLimitExceeded; +/// # +/// if depth > MAX_DEPTH { +/// bail!(ScienceError::RecursionLimitExceeded); +/// } +/// # Ok(()) +/// # } +/// ``` +#[macro_export] +macro_rules! bail { + ($msg:literal $(,)?) => { + return Err($crate::Diagnostic(std::sync::Arc::new(sol_eyre::eyre!($msg)))); + }; + ($err:expr $(,)?) => { + return Err($crate::Diagnostic(std::sync::Arc::new(sol_eyre::eyre!($err)))); + }; + ($fmt:expr, $($arg:tt)*) => { + return Err($crate::Diagnostic(std::sync::Arc::new(sol_eyre::eyre!($fmt, $($arg)*)))); + }; +} + +/// Return early with an error if a condition is not satisfied. +/// +/// This macro is equivalent to `if !$cond { return Err(From::from($err)); }`. +/// +/// Analogously to `assert!`, `ensure!` takes a condition and exits the function +/// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error` +/// rather than panicking. +/// +/// # Example +/// +/// ``` +/// # use sol_diagnostic::{ensure, Result}; +/// # +/// # fn main() -> Result<()> { +/// # let user = 0; +/// # +/// ensure!(user == 0, "only user 0 is allowed"); +/// # Ok(()) +/// # } +/// ``` +/// +/// ``` +/// # use sol_diagnostic::{ensure, Result}; +/// # use thiserror::Error; +/// # +/// # const MAX_DEPTH: usize = 1; +/// # +/// #[derive(Error, Debug)] +/// enum ScienceError { +/// #[error("recursion limit exceeded")] +/// RecursionLimitExceeded, +/// # #[error("...")] +/// # More = (stringify! { +/// ... +/// # }, 1).1, +/// } +/// +/// # fn main() -> Result<()> { +/// # let depth = 0; +/// # +/// ensure!(depth <= MAX_DEPTH, ScienceError::RecursionLimitExceeded); +/// # Ok(()) +/// # } +/// ``` +#[macro_export] +macro_rules! ensure { + ($cond:expr, $msg:literal $(,)?) => { + if !$cond { + return Err($crate::Diagnostic(std::sync::Arc::new(sol_eyre::eyre!($msg)))); + } + }; + ($cond:expr, $err:expr $(,)?) => { + if !$cond { + return Err($crate::Diagnostic(std::sync::Arc::new(sol_eyre::eyre!($err)))); + } + }; + ($cond:expr, $fmt:expr, $($arg:tt)*) => { + if !$cond { + return Err($crate::Diagnostic(std::sync::Arc::new(sol_eyre::eyre!($fmt, $($arg)*)))); + } + }; +} + +/// Construct an ad-hoc error from a string. +/// +/// This evaluates to an `Error`. It can take either just a string, or a format +/// string with arguments. It also can take any custom type which implements +/// `Debug` and `Display`. +/// +/// # Example +/// +/// ``` +/// # type V = (); +/// # +/// use sol_diagnostic::{eyre, Result}; +/// +/// fn lookup(key: &str) -> Result { +/// if key.len() != 16 { +/// return Err(eyre!("key length must be 16 characters, got {:?}", key)); +/// } +/// +/// // ... +/// # Ok(()) +/// } +/// ``` +#[macro_export] +macro_rules! eyre { + ($msg:literal $(,)?) => ({ + $crate::Diagnostic(std::sync::Arc::new(sol_eyre::eyre!($msg))) + }); + ($err:expr $(,)?) => ({ + $crate::Diagnostic(std::sync::Arc::new(sol_eyre::eyre!($err))) + }); + ($fmt:expr, $($arg:tt)*) => ({ + $crate::Diagnostic(std::sync::Arc::new(sol_eyre::eyre!($fmt, $($arg)*))) + }); +} diff --git a/sol-thir-lowering/src/infer.rs b/sol-thir-lowering/src/infer.rs index e73a1b5..5b1f4d0 100644 --- a/sol-thir-lowering/src/infer.rs +++ b/sol-thir-lowering/src/infer.rs @@ -1,3 +1,4 @@ +use sol_diagnostic::bail; use sol_thir::{ shared::{Constructor, ConstructorKind}, ElaboratedTerm, @@ -61,7 +62,7 @@ pub fn thir_infer( Call(_) => todo!(), Lam(_) => todo!(), Pi(_) => todo!(), - Sigma(_) => todo!(), + Sigma(_) => bail!("sigma types are not supported yet"), Hole(_) => { let meta = MetaVar::new(None); let term = Term::InsertedMeta(meta.clone());