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}