use core::fmt;
use ir_lang::{BuildError, FuncId, ModuleError, ValidationError};
use crate::pipeline::PassKind;
#[derive(Clone, PartialEq, Eq, Debug)]
#[non_exhaustive]
pub enum OptError {
Module(ModuleError),
InvalidInput {
func: FuncId,
error: ValidationError,
},
InvalidOutput {
func: FuncId,
pass: PassKind,
error: ValidationError,
},
Build {
func: FuncId,
pass: PassKind,
error: BuildError,
},
}
impl fmt::Display for OptError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
OptError::Module(e) => write!(f, "{e}"),
OptError::InvalidInput { func, error } => {
write!(f, "function {func} is not valid IR: {error}")
}
OptError::InvalidOutput { func, pass, error } => write!(
f,
"pass `{}` left function {func} invalid: {error}",
pass.name()
),
OptError::Build { func, pass, error } => write!(
f,
"pass `{}` could not rewrite function {func}: {error}",
pass.name()
),
}
}
}
impl core::error::Error for OptError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
OptError::Module(e) => Some(e),
OptError::InvalidInput { error, .. } | OptError::InvalidOutput { error, .. } => {
Some(error)
}
OptError::Build { error, .. } => Some(error),
}
}
}
impl From<ModuleError> for OptError {
fn from(e: ModuleError) -> Self {
OptError::Module(e)
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::ToString;
use core::error::Error;
#[test]
fn test_display_names_the_pass_and_function() {
let e = OptError::Build {
func: FuncId::from_u32(2),
pass: PassKind::Gvn,
error: BuildError::CapacityExceeded,
};
let text = e.to_string();
assert!(text.contains("gvn") && text.contains("f2"), "{text}");
assert!(e.source().is_some());
let m = OptError::from(ModuleError::NotDefined {
func: FuncId::from_u32(1),
});
assert!(m.source().is_some());
assert!(!m.to_string().is_empty());
}
}