Skip to main content

lady_deirdre/analysis/
error.rs

1////////////////////////////////////////////////////////////////////////////////
2// This file is part of "Lady Deirdre", a compiler front-end foundation       //
3// technology.                                                                //
4//                                                                            //
5// This work is proprietary software with source-available code.              //
6//                                                                            //
7// To copy, use, distribute, or contribute to this work, you must agree to    //
8// the terms of the General License Agreement:                                //
9//                                                                            //
10// https://github.com/Eliah-Lakhin/lady-deirdre/blob/master/EULA.md           //
11//                                                                            //
12// The agreement grants a Basic Commercial License, allowing you to use       //
13// this work in non-commercial and limited commercial products with a total   //
14// gross revenue cap. To remove this commercial limit for one of your         //
15// products, you must acquire a Full Commercial License.                      //
16//                                                                            //
17// If you contribute to the source code, documentation, or related materials, //
18// you must grant me an exclusive license to these contributions.             //
19// Contributions are governed by the "Contributions" section of the General   //
20// License Agreement.                                                         //
21//                                                                            //
22// Copying the work in parts is strictly forbidden, except as permitted       //
23// under the General License Agreement.                                       //
24//                                                                            //
25// If you do not or cannot agree to the terms of this Agreement,              //
26// do not use this work.                                                      //
27//                                                                            //
28// This work is provided "as is", without any warranties, express or implied, //
29// except where such disclaimers are legally invalid.                         //
30//                                                                            //
31// Copyright (c) 2024 Ilya Lakhin (Илья Александрович Лахин).                 //
32// All rights reserved.                                                       //
33////////////////////////////////////////////////////////////////////////////////
34
35use std::{
36    error::Error,
37    fmt::{Display, Formatter},
38};
39
40/// A result of the semantic analysis.
41///
42/// See [AnalysisError] for details.
43pub type AnalysisResult<T> = Result<T, AnalysisError>;
44
45/// An error occurring during semantics analysis.
46///
47/// There are two types of errors:
48///
49///   - An [abnormal](AnalysisError::is_abnormal) that indicate an error
50///     in the user code, such as an issue in
51///     the [Grammar](crate::analysis::Grammar) configuration or misuse
52///     of the analysis API. In this case, it is recommended to panic as early
53///     as possible such that the panic backtrace will point to the exact piece
54///     of code of where the error occurred.
55///
56///   - A normal error that should be propagated up to the caller of the current
57///     function that returns an [AnalysisResult]. For example, such errors
58///     should be returned from
59///     the [Computable::compute](crate::analysis::Computable::compute)
60///     implementations.
61///
62/// For convenience, the [AnalysisResult] type extended by
63/// the [AnalysisResultEx] trait with the [AnalysisResultEx::unwrap_abnormal]
64/// function that panics in place if the underlying error is abnormal, or
65/// passes the Result object through if the underlying variant is Ok or denotes
66/// a normal error.
67///
68/// Currently, the AnalysisError defines two normal errors:
69///
70///  - The [Interrupted](AnalysisError::Interrupted) error, which denotes that
71///    the operation cannot be completed, because the underlying task has been
72///    [signaled](crate::analysis::TaskHandle::is_triggered) to shut down.
73///
74///  - The [Timeout](AnalysisError::Timeout) error, which denotes that
75///    the operation computation exceeded predefined timeout. This error may
76///    occur due to recursion in the attributes graph, which is a user code
77///    issue, or just a normal time out if the operation takes too long.
78///    In the production builds (when the `debug_assertions` feature
79///    is disabled), this type of error is a normal error, but in non-production
80///    builds, this error considered abnormal.
81#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
82#[non_exhaustive]
83pub enum AnalysisError {
84    /// The operation cannot be completed because the underlying task has been
85    /// [signaled](crate::analysis::TaskHandle::is_triggered) to shut down.
86    ///
87    /// This error is a **normal** error.
88    Interrupted,
89
90    /// The document referred to by the specified [id](crate::arena::Id) does
91    /// not exits in the Analyzer.
92    ///
93    /// This error is an **abnormal** error.
94    MissingDocument,
95
96    /// The [content edit](crate::analysis::MutationAccess::write_to_doc)
97    /// operation cannot be performed on the specified document, because
98    /// the document is
99    /// [not mutable](crate::analysis::MutationAccess::add_immutable_doc).
100    ///
101    /// This error is an **abnormal** error.
102    ImmutableDocument,
103
104    /// The specified [span](crate::lexis::ToSpan) is not valid for
105    /// the specified document.
106    ///
107    /// This error is an **abnormal** error.
108    InvalidSpan,
109
110    /// An attempt to access an [Attr](crate::analysis::Attr) object which is
111    /// not fully initialized.
112    ///
113    /// See [Feature Lifetime](crate::analysis::Feature#feature-lifetime) for details.
114    ///
115    /// This error is an **abnormal** error.
116    UninitAttribute,
117
118    /// An attempt to access an [Slot](crate::analysis::Slot) object which is
119    /// not fully initialized.
120    ///
121    /// See [Feature Lifetime](crate::analysis::Feature#feature-lifetime) for details.
122    ///
123    /// This error is an **abnormal** error.
124    UninitSlot,
125
126    /// The referred attribute does not exist in the Analyzer's semantic graph.
127    ///
128    /// This error is an **abnormal** error.
129    MissingAttribute,
130
131    /// The referred slot does not exist in the Analyzer's semantic graph.
132    ///
133    /// This error is an **abnormal** error.
134    MissingSlot,
135
136    /// An attempt to access a [Semantics](crate::analysis::Semantics) object
137    /// which is not fully initialized.
138    ///
139    /// See [Feature Lifetime](crate::analysis::Feature#feature-lifetime) for details.
140    ///
141    /// This error is an **abnormal** error.
142    UninitSemantics,
143
144    /// The specified syntax tree node does not have semantics.
145    ///
146    /// This error may occur, for example, if
147    /// the [Grammar](crate::analysis::Grammar) object does not specify any
148    /// semantics for any node, or if a particular type of the node does not
149    /// specify semantics.
150    ///
151    /// This error is an **abnormal** error.
152    MissingSemantics,
153
154    /// The [attribute](crate::analysis::Attr) value type is differ from
155    /// the specified type.
156    ///
157    /// This error is an **abnormal** error.
158    TypeMismatch,
159
160    /// The specified feature does not exist in the syntax tree node's
161    /// semantics.
162    ///
163    /// This error is an **abnormal** error.
164    MissingFeature,
165
166    /// Operation timeout.
167    ///
168    /// This error indicates that the requested operation takes too long to
169    /// finish, which is generally acceptable, or if the semantics graph has
170    /// a recursion, which is an issue in the semantics design.
171    ///
172    /// This error is a **normal** error if the target build is a production
173    /// build (`debug_assertions` feature is disabled). Otherwise, the error is
174    /// **abnormal**.
175    Timeout,
176}
177
178impl Display for AnalysisError {
179    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
180        let text = match self {
181            Self::Interrupted => "Analysis task was interrupted.",
182            Self::MissingDocument => "Referred document does not exist in the analyzer.",
183            Self::ImmutableDocument => "An attempt to write into immutable document.",
184            Self::InvalidSpan => "Provided span is not valid for the specified document.",
185            Self::UninitAttribute => "An attempt to access uninitialized attribute object.",
186            Self::UninitSlot => "An attempt to access uninitialized slot object.",
187            Self::MissingAttribute => "Referred attribute does not exist in the analyzer.",
188            Self::MissingSlot => "Referred slot does not exist in the analyzer.",
189            Self::UninitSemantics => "An attempt to access uninitialized semantics object.",
190            Self::MissingSemantics => "Node variant does not have semantics.",
191            Self::TypeMismatch => "Incorrect attribute type.",
192            Self::MissingFeature => "An attempt to access semantic feature that does not exist.",
193            Self::Timeout => "Attribute computation timeout.",
194        };
195
196        formatter.write_str(text)
197    }
198}
199
200impl Error for AnalysisError {}
201
202impl AnalysisError {
203    /// Returns true if the underlying error object denotes an issue in
204    /// the user code, or in the [Grammar](crate::analysis::Grammar)
205    /// configuration.
206    #[inline(always)]
207    pub fn is_abnormal(&self) -> bool {
208        match self {
209            Self::Interrupted => false,
210            Self::Timeout => cfg!(debug_assertions),
211            _ => true,
212        }
213    }
214}
215
216/// An helper extension of the [AnalysisResult].
217///
218/// The trait provides a function that unwraps
219/// [abnormal](AnalysisError::is_abnormal) errors or passes the result object
220/// through if the underlying error is normal or the result is Ok.
221///
222/// See [AnalysisError] for details.
223pub trait AnalysisResultEx<T> {
224    /// Panics in places with caller-tracking if the Result is
225    /// an [abnormal](AnalysisError::is_abnormal) error; otherwise returns
226    /// `self`.
227    ///
228    /// The intended use of this function is convenient unwrapping of
229    /// the abnormal results in the call chain code:
230    ///
231    /// ```ignore
232    /// let attr_read_guard = my_attr.read().unwrap_abnormal()?;
233    /// ```
234    fn unwrap_abnormal(self) -> AnalysisResult<T>;
235}
236
237impl<T> AnalysisResultEx<T> for AnalysisResult<T> {
238    #[track_caller]
239    #[inline(always)]
240    fn unwrap_abnormal(self) -> AnalysisResult<T> {
241        match self {
242            Ok(ok) => Ok(ok),
243            Err(error) if !error.is_abnormal() => Err(error),
244            Err(error) => panic!("Analysis internal error. {error}"),
245        }
246    }
247}