Skip to main content

lean_rs_host/host/process/
outcome.rs

1//! Typed outcomes for the two info-tree projection shims on
2//! [`crate::LeanSession`].
3//!
4//! - [`ProcessFileOutcome`] is what
5//!   [`crate::LeanSession::process_with_info_tree`] returns: the
6//!   body-only projection plus the `Unsupported` degradation arm.
7//! - [`ProcessModuleOutcome`] is what
8//!   [`crate::LeanSession::process_module_with_info_tree`] returns: three
9//!   real arms (`Ok`, `MissingImports`, `HeaderParseFailed`) plus the
10//!   same `Unsupported` degradation. The arms distinguish a cleanly
11//!   parsed header whose body elaborated, a cleanly parsed header
12//!   whose imports the session's open env does not have (soft
13//!   failure — the body still runs against the env), and a header
14//!   that did not parse at all (the body is never elaborated).
15//!
16//! Heartbeat exhaustion during a single command's elaboration surfaces
17//! as an error-severity entry in `ProcessedFile::diagnostics`, not a
18//! separate wire arm — `IO.processCommands` catches per-command
19//! exceptions and attaches them to the message log on both shims.
20
21use lean_rs::Obj;
22use lean_rs::abi::structure::{ctor_tag, take_ctor_objects};
23use lean_rs::abi::traits::{TryFromLean, conversion_error};
24use lean_rs::error::LeanResult;
25
26use crate::host::elaboration::LeanElabFailure;
27use crate::host::process::info_tree::ProcessedFile;
28
29/// Outcome of [`crate::LeanSession::process_with_info_tree`].
30#[derive(Debug)]
31pub enum ProcessFileOutcome {
32    /// The elaborator ran and produced an `Elab.InfoTree` projection.
33    /// `ProcessedFile::diagnostics` carries every error-severity entry
34    /// the elaborator emitted; callers that need to distinguish
35    /// heartbeat exhaustion from other failures should match on the
36    /// diagnostics there.
37    Processed(ProcessedFile),
38    /// The capability dylib does not export the
39    /// `lean_rs_host_process_with_info_tree` shim. No FFI call was
40    /// made; callers can fall back or degrade as appropriate.
41    Unsupported,
42}
43
44/// Outcome of [`crate::LeanSession::process_module_with_info_tree`].
45///
46/// The Lean shim parses the header first (via `Lean.Parser.parseHeader`)
47/// and only runs `IO.processCommands` if the header parsed cleanly.
48/// `Ok` / `MissingImports` therefore both carry a populated
49/// [`ProcessedFile`] (its `diagnostics` field captures any elaboration
50/// failure of the body); `HeaderParseFailed` short-circuits with just
51/// the parser's diagnostics.
52#[derive(Debug)]
53pub enum ProcessModuleOutcome {
54    /// Header parsed; every parsed import is present in the session's
55    /// open env; the body was processed. `imports` lists the
56    /// user-written modules (Lean's auto-inserted `Init` is filtered
57    /// out by the shim).
58    Ok {
59        /// Body projection. `file.diagnostics` still records any
60        /// per-command elaboration errors the body produced.
61        file: ProcessedFile,
62        /// User-written imports from the file's header.
63        imports: Vec<String>,
64    },
65    /// Header parsed but some imports name modules the session's open
66    /// env does not have. The body was still processed against the
67    /// available env — `file` is populated and the partial projection
68    /// is useful diagnostic data. Callers typically surface `missing`
69    /// as a warning.
70    MissingImports {
71        /// Body projection (partial if some declarations depended on
72        /// the missing modules).
73        file: ProcessedFile,
74        /// User-written imports from the file's header.
75        imports: Vec<String>,
76        /// Subset of `imports` not present in the session's open env.
77        missing: Vec<String>,
78    },
79    /// `Lean.Parser.parseHeader` reported error-severity messages.
80    /// `IO.processCommands` was not invoked; only the header
81    /// diagnostics are returned.
82    HeaderParseFailed {
83        /// Header-parser diagnostics, with the same byte-budget
84        /// semantics as
85        /// [`crate::host::evidence::LeanKernelOutcome::Rejected`].
86        diagnostics: LeanElabFailure,
87    },
88    /// The capability dylib does not export the
89    /// `lean_rs_host_process_module_with_info_tree` shim. No FFI call was
90    /// made.
91    Unsupported,
92}
93
94impl<'lean> TryFromLean<'lean> for ProcessModuleOutcome {
95    fn try_from_lean(obj: Obj<'lean>) -> LeanResult<Self> {
96        // The Lean inductive has three constructors:
97        //   tag 0 = .ok               (file, imports)
98        //   tag 1 = .missingImports   (file, imports, missing)
99        //   tag 2 = .headerParseFailed(diagnostics)
100        // `Unsupported` is synthesised on the Rust side and never
101        // crosses the FFI, mirroring the existing pattern on
102        // `ProcessFileOutcome`.
103        let tag = ctor_tag(&obj)?;
104        match tag {
105            0 => {
106                let [file, imports] = take_ctor_objects::<2>(obj, 0, "ProcessModuleOutcome::ok")?;
107                Ok(Self::Ok {
108                    file: ProcessedFile::try_from_lean(file)?,
109                    imports: Vec::<String>::try_from_lean(imports)?,
110                })
111            }
112            1 => {
113                let [file, imports, missing] = take_ctor_objects::<3>(obj, 1, "ProcessModuleOutcome::missingImports")?;
114                Ok(Self::MissingImports {
115                    file: ProcessedFile::try_from_lean(file)?,
116                    imports: Vec::<String>::try_from_lean(imports)?,
117                    missing: Vec::<String>::try_from_lean(missing)?,
118                })
119            }
120            2 => {
121                let [diagnostics] = take_ctor_objects::<1>(obj, 2, "ProcessModuleOutcome::headerParseFailed")?;
122                Ok(Self::HeaderParseFailed {
123                    diagnostics: LeanElabFailure::try_from_lean(diagnostics)?,
124                })
125            }
126            other => Err(conversion_error(format!(
127                "expected Lean ProcessModuleOutcome ctor (tag 0..=2), found tag {other}"
128            ))),
129        }
130    }
131}