use core::fmt;
use symbol_lang::Symbol;
use crate::id::ModuleId;
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum ResolveError {
UnknownModule(ModuleId),
DuplicateName {
module: ModuleId,
name: Symbol,
},
Unresolved {
module: ModuleId,
name: Symbol,
},
Private {
module: ModuleId,
name: Symbol,
},
ImportCycle {
module: ModuleId,
name: Symbol,
},
}
impl fmt::Display for ResolveError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnknownModule(id) => {
write!(f, "module id {} was not minted by this graph", id.to_u32())
}
Self::DuplicateName { module, name } => write!(
f,
"name (symbol {}) is already declared in module {}",
name.as_u32(),
module.to_u32(),
),
Self::Unresolved { module, name } => write!(
f,
"no name (symbol {}) is declared in module {}",
name.as_u32(),
module.to_u32(),
),
Self::Private { module, name } => write!(
f,
"name (symbol {}) in module {} is private and cannot be imported",
name.as_u32(),
module.to_u32(),
),
Self::ImportCycle { module, name } => write!(
f,
"import of name (symbol {}) forms a cycle at module {}",
name.as_u32(),
module.to_u32(),
),
}
}
}
impl core::error::Error for ResolveError {}
#[cfg(test)]
#[allow(
clippy::expect_used,
reason = "unwrapping a known-good setup is fine in tests"
)]
mod tests {
extern crate alloc;
use alloc::string::ToString;
use super::*;
#[test]
fn test_unknown_module_display_names_the_id() {
let err = ResolveError::UnknownModule(ModuleId::from_index(4));
assert!(err.to_string().contains('4'), "{err}");
}
#[test]
fn test_duplicate_display_names_module_and_symbol() {
let err = ResolveError::DuplicateName {
module: ModuleId::from_index(2),
name: Symbol::from_u32(7).expect("nonzero"),
};
let text = err.to_string();
assert!(text.contains('2'), "{text}");
assert!(text.contains('7'), "{text}");
}
#[test]
fn test_error_is_clonable_and_equatable() {
let a = ResolveError::Unresolved {
module: ModuleId::from_index(1),
name: Symbol::from_u32(1).expect("nonzero"),
};
let b = a.clone();
assert_eq!(a, b);
}
}