1use core::fmt;
4
5use ir_lang::ValidationError;
6
7#[derive(Clone, PartialEq, Debug)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37#[non_exhaustive]
38pub enum CodegenError {
39 InvalidIr(ValidationError),
44}
45
46impl fmt::Display for CodegenError {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 match self {
49 CodegenError::InvalidIr(reason) => {
50 write!(
51 f,
52 "cannot lower a function that is not well-formed: {reason}"
53 )
54 }
55 }
56 }
57}
58
59impl core::error::Error for CodegenError {
60 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
61 match self {
62 CodegenError::InvalidIr(reason) => Some(reason),
63 }
64 }
65}
66
67impl From<ValidationError> for CodegenError {
68 fn from(reason: ValidationError) -> Self {
69 CodegenError::InvalidIr(reason)
70 }
71}
72
73#[cfg(test)]
74#[allow(
75 clippy::unwrap_used,
76 clippy::expect_used,
77 clippy::panic,
78 reason = "tests assert on specific outcomes; a wrong outcome should fail the test loudly"
79)]
80mod tests {
81 use super::CodegenError;
82 use crate::compile;
83 use ir_lang::{Builder, Type, ValidationError};
84
85 #[test]
86 fn test_invalid_ir_error_wraps_the_validation_reason() {
87 let func = Builder::new("f", &[], Type::Unit).finish();
88 let err = match compile(&func) {
89 Err(e) => e,
90 Ok(_) => panic!("an unterminated function must not compile"),
91 };
92 assert!(matches!(
93 err,
94 CodegenError::InvalidIr(ValidationError::MissingTerminator { .. })
95 ));
96 }
97
98 #[test]
99 fn test_display_carries_the_underlying_reason() {
100 let func = Builder::new("f", &[], Type::Int).finish();
101 let err = compile(&func).expect_err("non-unit function with no return is invalid");
102 let text = err.to_string();
103 assert!(text.starts_with("cannot lower a function that is not well-formed"));
104 }
105
106 #[test]
107 fn test_error_source_is_the_validation_error() {
108 use core::error::Error;
109 let func = Builder::new("f", &[], Type::Unit).finish();
110 let err = compile(&func).expect_err("unterminated function is invalid");
111 assert!(err.source().is_some());
112 }
113
114 #[test]
115 fn test_from_validation_error_constructs_invalid_ir() {
116 let func = Builder::new("f", &[], Type::Unit).finish();
117 let reason = func
118 .validate()
119 .expect_err("unterminated function is invalid");
120 let err: CodegenError = reason.into();
121 assert!(matches!(err, CodegenError::InvalidIr(_)));
122 }
123}