#![allow(unsafe_code)]
use core::fmt;
use lean_rs_sys::ctor::lean_ctor_get_uint8;
use crate::host::elaboration::diagnostic::{LeanDiagnostic, LeanSeverity};
use lean_rs::Obj;
use lean_rs::abi::structure::{ctor_tag, take_ctor_objects};
use lean_rs::abi::traits::{TryFromLean, conversion_error};
use lean_rs::error::{LeanDiagnosticCode, LeanResult};
#[derive(Clone, Debug)]
pub struct LeanElabFailure {
diagnostics: Vec<LeanDiagnostic>,
truncated: bool,
}
impl LeanElabFailure {
#[must_use]
pub fn diagnostics(&self) -> &[LeanDiagnostic] {
&self.diagnostics
}
#[must_use]
pub fn truncated(&self) -> bool {
self.truncated
}
#[must_use]
pub const fn code(&self) -> LeanDiagnosticCode {
LeanDiagnosticCode::Elaboration
}
pub(crate) fn synthetic(message: String, file_label: String) -> Self {
Self {
diagnostics: vec![LeanDiagnostic::synthetic_error(message, file_label)],
truncated: false,
}
}
}
impl fmt::Display for LeanElabFailure {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(first_error) = self.diagnostics.iter().find(|d| d.severity() == LeanSeverity::Error) {
return f.write_str(first_error.message());
}
if let Some(first) = self.diagnostics.first() {
return f.write_str(first.message());
}
f.write_str("elaboration failed (no diagnostics)")
}
}
impl std::error::Error for LeanElabFailure {}
impl<'lean> TryFromLean<'lean> for LeanElabFailure {
fn try_from_lean(obj: Obj<'lean>) -> LeanResult<Self> {
let tag = ctor_tag(&obj)?;
if tag != 0 {
return Err(conversion_error(format!(
"expected Lean ElabFailure ctor (tag 0), found tag {tag}"
)));
}
let ptr = obj.as_raw_borrowed();
let truncated_byte = unsafe { lean_ctor_get_uint8(ptr, 0) };
let truncated = match truncated_byte {
0 => false,
1 => true,
other => {
return Err(conversion_error(format!(
"Lean Truncation tag {other} is not in {{0=complete, 1=truncated}}"
)));
}
};
let [diagnostics_o] = take_ctor_objects::<1>(obj, 0, "ElabFailure")?;
let diagnostics = Vec::<LeanDiagnostic>::try_from_lean(diagnostics_o)?;
Ok(Self { diagnostics, truncated })
}
}