1use crate::context::{DiagnosticVoucher, NamedThing};
4use fe_common::diagnostics::{Diagnostic, Label, Severity};
5use fe_common::Span;
6use std::fmt::Display;
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
27pub struct TypeError(DiagnosticVoucher);
28impl TypeError {
29 pub fn new(voucher: DiagnosticVoucher) -> Self {
32 Self(voucher)
33 }
34}
35
36impl From<FatalError> for TypeError {
37 fn from(err: FatalError) -> Self {
38 Self(err.0)
39 }
40}
41impl From<ConstEvalError> for TypeError {
42 fn from(err: ConstEvalError) -> Self {
43 Self(err.0)
44 }
45}
46
47#[derive(Debug)]
51pub struct FatalError(DiagnosticVoucher);
52
53impl FatalError {
54 pub fn new(voucher: DiagnosticVoucher) -> Self {
57 Self(voucher)
58 }
59}
60
61impl From<ConstEvalError> for FatalError {
62 fn from(err: ConstEvalError) -> Self {
63 Self(err.0)
64 }
65}
66
67impl From<AlreadyDefined> for FatalError {
68 fn from(err: AlreadyDefined) -> Self {
69 Self(err.0)
70 }
71}
72
73#[derive(Debug, Clone, PartialEq, Eq, Hash)]
86pub struct ConstEvalError(DiagnosticVoucher);
87
88impl ConstEvalError {
89 pub fn new(voucher: DiagnosticVoucher) -> Self {
90 Self(voucher)
91 }
92}
93
94impl From<TypeError> for ConstEvalError {
95 fn from(err: TypeError) -> Self {
96 Self(err.0)
97 }
98}
99
100impl From<FatalError> for ConstEvalError {
101 fn from(err: FatalError) -> Self {
102 Self(err.0)
103 }
104}
105
106impl From<IncompleteItem> for ConstEvalError {
107 fn from(err: IncompleteItem) -> Self {
108 Self(err.0)
109 }
110}
111
112#[derive(Debug)]
117pub struct IncompleteItem(DiagnosticVoucher);
118impl IncompleteItem {
119 #[allow(clippy::new_without_default)]
120 pub fn new() -> Self {
121 Self(DiagnosticVoucher::assume_the_parser_handled_it())
122 }
123}
124
125#[derive(Debug)]
127pub struct AlreadyDefined(DiagnosticVoucher);
128impl AlreadyDefined {
129 #[allow(clippy::new_without_default)]
130 pub fn new(voucher: DiagnosticVoucher) -> Self {
131 Self(voucher)
132 }
133}
134
135#[derive(Debug, PartialEq, Eq)]
137pub enum IndexingError {
138 WrongIndexType,
139 NotSubscriptable,
140}
141
142#[derive(Debug, PartialEq, Eq)]
144pub enum BinaryOperationError {
145 TypesNotCompatible,
146 TypesNotNumeric,
147 RightTooLarge,
148 RightIsSigned,
149 NotEqualAndUnsigned,
150}
151
152#[derive(Debug, PartialEq, Eq)]
154pub enum TypeCoercionError {
155 RequiresToMem,
157 Incompatible,
159 SelfContractType,
161}
162
163impl From<TypeError> for FatalError {
164 fn from(err: TypeError) -> Self {
165 Self::new(err.0)
166 }
167}
168
169impl From<IncompleteItem> for FatalError {
170 fn from(err: IncompleteItem) -> Self {
171 Self::new(err.0)
172 }
173}
174
175impl From<IncompleteItem> for TypeError {
176 fn from(err: IncompleteItem) -> Self {
177 Self::new(err.0)
178 }
179}
180
181pub fn error(message: impl Into<String>, label_span: Span, label: impl Into<String>) -> Diagnostic {
182 fancy_error(message, vec![Label::primary(label_span, label)], vec![])
183}
184
185pub fn fancy_error(
186 message: impl Into<String>,
187 labels: Vec<Label>,
188 notes: Vec<String>,
189) -> Diagnostic {
190 Diagnostic {
191 severity: Severity::Error,
192 message: message.into(),
193 labels,
194 notes,
195 }
196}
197
198pub fn type_error(
199 message: impl Into<String>,
200 span: Span,
201 expected: impl Display,
202 actual: impl Display,
203) -> Diagnostic {
204 error(
205 message,
206 span,
207 format!("this has type `{actual}`; expected type `{expected}`"),
208 )
209}
210
211pub fn not_yet_implemented(feature: impl Display, span: Span) -> Diagnostic {
212 error(
213 format!("feature not yet implemented: {feature}"),
214 span,
215 "not yet implemented",
216 )
217}
218
219pub fn duplicate_name_error(
220 message: &str,
221 name: &str,
222 original: Span,
223 duplicate: Span,
224) -> Diagnostic {
225 fancy_error(
226 message,
227 vec![
228 Label::primary(original, format!("`{name}` first defined here")),
229 Label::secondary(duplicate, format!("`{name}` redefined here")),
230 ],
231 vec![],
232 )
233}
234
235pub fn name_conflict_error(
236 name_kind: &str, name: &str,
238 original: &NamedThing,
239 original_span: Option<Span>,
240 duplicate_span: Span,
241) -> Diagnostic {
242 if let Some(original_span) = original_span {
243 fancy_error(
244 format!(
245 "{} name `{}` conflicts with previously defined {}",
246 name_kind,
247 name,
248 original.item_kind_display_name()
249 ),
250 vec![
251 Label::primary(original_span, format!("`{name}` first defined here")),
252 Label::secondary(duplicate_span, format!("`{name}` redefined here")),
253 ],
254 vec![],
255 )
256 } else {
257 fancy_error(
258 format!(
259 "{} name `{}` conflicts with built-in {}",
260 name_kind,
261 name,
262 original.item_kind_display_name()
263 ),
264 vec![Label::primary(
265 duplicate_span,
266 format!(
267 "`{}` is a built-in {}",
268 name,
269 original.item_kind_display_name()
270 ),
271 )],
272 vec![],
273 )
274 }
275}
276
277pub fn to_mem_error(span: Span) -> Diagnostic {
278 fancy_error(
279 "value must be copied to memory",
280 vec![Label::primary(span, "this value is in storage")],
281 vec![
282 "Hint: values located in storage can be copied to memory using the `to_mem` function."
283 .into(),
284 "Example: `self.my_array.to_mem()`".into(),
285 ],
286 )
287}
288pub fn self_contract_type_error(span: Span, typ: &dyn Display) -> Diagnostic {
289 fancy_error(
290 format!("`self` can't be used where a contract of type `{typ}` is expected",),
291 vec![Label::primary(span, "cannot use `self` here")],
292 vec![format!(
293 "Hint: Values of type `{typ}` represent external contracts.\n\
294 To treat `self` as an external contract, use `{typ}(ctx.self_address())`."
295 )],
296 )
297}