Skip to main content

geam_core/runtime/
error.rs

1mod diagnostic;
2mod host;
3mod invariant;
4mod panic;
5
6use crate::plan::{PanicSite, SourceContext, SourceSpan};
7use crate::runtime::Value;
8use ecow::EcoString;
9
10pub(crate) use self::host::HostCallOrigin;
11pub use self::host::{HostError, HostLocation, HostOrigin};
12pub use self::invariant::InvariantError;
13pub use self::panic::{BitArraySegmentPanicReason, Panic, PanicDetails, PanicKind, PanicMessage};
14
15#[derive(Debug, Clone, PartialEq, thiserror::Error)]
16pub enum ExecutionError {
17    #[error("{0}")]
18    Panic(Panic),
19    #[error("{0}")]
20    Invariant(InvariantError),
21    #[error("{0}")]
22    Host(Box<HostError>),
23}
24
25pub(crate) type ExecutionResult<T> = Result<T, ExecutionError>;
26
27impl ExecutionError {
28    pub(crate) fn from_host_call(
29        function: &crate::plan::execution::host::HostedFunctionMetadata,
30        site: crate::plan::HostCallSite,
31        source_context: Option<&SourceContext>,
32        failure: crate::HostFailure,
33    ) -> Self {
34        Self::Host(Box::new(HostError::new(
35            function.package().clone(),
36            function.module().clone(),
37            function.name().clone(),
38            function.signature().clone(),
39            failure,
40            site,
41            source_context,
42        )))
43    }
44
45    pub(crate) fn from_host_origin(
46        function: &crate::plan::execution::host::HostedFunctionMetadata,
47        caller: HostOrigin,
48        failure: crate::HostFailure,
49    ) -> Self {
50        Self::Host(Box::new(HostError::new_from_host(
51            function.package().clone(),
52            function.module().clone(),
53            function.name().clone(),
54            function.signature().clone(),
55            failure,
56            caller,
57        )))
58    }
59
60    pub(crate) fn source_panic(
61        source_context: Option<&SourceContext>,
62        kind: PanicKind,
63        message: Option<EcoString>,
64        site: PanicSite,
65    ) -> Self {
66        Self::Panic(Panic::new(
67            kind,
68            PanicMessage::from_optional_explicit(message),
69            site,
70            source_context,
71            None,
72        ))
73    }
74
75    pub(crate) fn let_assert_panic(
76        source_context: Option<&SourceContext>,
77        message: Option<EcoString>,
78        site: PanicSite,
79        value: Value,
80        pattern_span: SourceSpan,
81    ) -> Self {
82        Self::Panic(Panic::new(
83            PanicKind::LetAssert,
84            PanicMessage::from_optional_explicit(message),
85            site,
86            source_context,
87            Some(PanicDetails::LetAssert {
88                value,
89                pattern_span,
90            }),
91        ))
92    }
93
94    pub(crate) fn bit_array_segment_panic(
95        source_context: Option<&SourceContext>,
96        reason: BitArraySegmentPanicReason,
97        site: PanicSite,
98    ) -> Self {
99        Self::Panic(Panic::new(
100            PanicKind::BitArraySegment,
101            PanicMessage::Default,
102            site,
103            source_context,
104            Some(PanicDetails::BitArraySegment { reason }),
105        ))
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::{ExecutionError, InvariantError};
112    use crate::plan::execution::function::FunctionReturnFamily;
113
114    #[test]
115    fn invariant_display_delegates_to_invariant_error() {
116        let invariant = InvariantError::FunctionReturnFamilyMismatch {
117            expected: FunctionReturnFamily::Int,
118            actual: FunctionReturnFamily::String,
119        };
120        let error = ExecutionError::Invariant(invariant);
121
122        assert_eq!(
123            error.to_string(),
124            "function return family mismatch (expected Int, got String)",
125        );
126    }
127}