1 //! The `darling::Error` type, the multiple error `Accumulator`, and their internals.
2 //!
3 //! Error handling is one of the core values of `darling`; creating great errors is hard and
4 //! never the reason that a proc-macro author started writing their crate. As a result, the
5 //! `Error` type in `darling` tries to make adding span information, suggestions, and other
6 //! help content easy when manually implementing `darling` traits, and automatic when deriving
7 //! them.
8 
9 use proc_macro2::{Span, TokenStream};
10 use std::error::Error as StdError;
11 use std::fmt;
12 use std::iter::{self, Iterator};
13 use std::string::ToString;
14 use std::vec;
15 use syn::spanned::Spanned;
16 use syn::{Expr, Lit, LitStr, Path};
17 
18 #[cfg(feature = "diagnostics")]
19 mod child;
20 mod kind;
21 
22 use crate::util::path_to_string;
23 
24 use self::kind::{ErrorKind, ErrorUnknownField};
25 
26 /// An alias of `Result` specific to attribute parsing.
27 pub type Result<T> = ::std::result::Result<T, Error>;
28 
29 /// An error encountered during attribute parsing.
30 ///
31 /// Given that most errors darling encounters represent code bugs in dependent crates,
32 /// the internal structure of the error is deliberately opaque.
33 ///
34 /// # Usage
35 /// Proc-macro expansion happens very infrequently compared to runtime tasks such as
36 /// deserialization, and it happens in the context of an expensive compilation taks.
37 /// For that reason, darling prefers not to fail on the first error it encounters, instead
38 /// doing as much work as it can, accumulating errors into a single report.
39 ///
40 /// As a result, `darling::Error` is more of guaranteed-non-empty error collection
41 /// than a single problem. These errors also have some notion of hierarchy, stemming from
42 /// the hierarchical nature of darling's input.
43 ///
44 /// These characteristics make for great experiences when using darling-powered crates,
45 /// provided crates using darling adhere to some best practices:
46 ///
47 /// 1. Do not attempt to simplify a `darling::Error` into some other error type, such as
48 ///    `syn::Error`. To surface compile errors, instead use `darling::Error::write_errors`.
49 ///    This preserves all span information, suggestions, etc. Wrapping a `darling::Error` in
50 ///    a custom error enum works as-expected and does not force any loss of fidelity.
51 /// 2. Do not use early return (e.g. the `?` operator) for custom validations. Instead,
52 ///    create an [`error::Accumulator`](Accumulator) to collect errors as they are encountered.  Then use
53 ///    [`Accumulator::finish`] to return your validated result; it will give `Ok` if and only if
54 ///    no errors were encountered.  This can create very complex custom validation functions;
55 ///    in those cases, split independent "validation chains" out into their own functions to
56 ///    keep the main validator manageable.
57 /// 3. Use `darling::Error::custom` to create additional errors as-needed, then call `with_span`
58 ///    to ensure those errors appear in the right place. Use `darling::util::SpannedValue` to keep
59 ///    span information around on parsed fields so that custom diagnostics can point to the correct
60 ///    parts of the input AST.
61 #[derive(Debug, Clone)]
62 pub struct Error {
63     kind: ErrorKind,
64     locations: Vec<String>,
65     /// The span to highlight in the emitted diagnostic.
66     span: Option<Span>,
67     /// Additional diagnostic messages to show with the error.
68     #[cfg(feature = "diagnostics")]
69     children: Vec<child::ChildDiagnostic>,
70 }
71 
72 /// Error creation functions
73 impl Error {
new(kind: ErrorKind) -> Self74     pub(in crate::error) fn new(kind: ErrorKind) -> Self {
75         Error {
76             kind,
77             locations: Vec::new(),
78             span: None,
79             #[cfg(feature = "diagnostics")]
80             children: vec![],
81         }
82     }
83 
84     /// Creates a new error with a custom message.
custom<T: fmt::Display>(msg: T) -> Self85     pub fn custom<T: fmt::Display>(msg: T) -> Self {
86         Error::new(ErrorKind::Custom(msg.to_string()))
87     }
88 
89     /// Creates a new error for a field that appears twice in the input.
duplicate_field(name: &str) -> Self90     pub fn duplicate_field(name: &str) -> Self {
91         Error::new(ErrorKind::DuplicateField(name.into()))
92     }
93 
94     /// Creates a new error for a field that appears twice in the input. Helper to avoid repeating
95     /// the syn::Path to String conversion.
duplicate_field_path(path: &Path) -> Self96     pub fn duplicate_field_path(path: &Path) -> Self {
97         Error::duplicate_field(&path_to_string(path))
98     }
99 
100     /// Creates a new error for a non-optional field that does not appear in the input.
missing_field(name: &str) -> Self101     pub fn missing_field(name: &str) -> Self {
102         Error::new(ErrorKind::MissingField(name.into()))
103     }
104 
105     /// Creates a new error for a field name that appears in the input but does not correspond
106     /// to a known field.
unknown_field(name: &str) -> Self107     pub fn unknown_field(name: &str) -> Self {
108         Error::new(ErrorKind::UnknownField(name.into()))
109     }
110 
111     /// Creates a new error for a field name that appears in the input but does not correspond
112     /// to a known field. Helper to avoid repeating the syn::Path to String conversion.
unknown_field_path(path: &Path) -> Self113     pub fn unknown_field_path(path: &Path) -> Self {
114         Error::unknown_field(&path_to_string(path))
115     }
116 
117     /// Creates a new error for a field name that appears in the input but does not correspond to
118     /// a known attribute. The second argument is the list of known attributes; if a similar name
119     /// is found that will be shown in the emitted error message.
unknown_field_with_alts<'a, T, I>(field: &str, alternates: I) -> Self where T: AsRef<str> + 'a, I: IntoIterator<Item = &'a T>,120     pub fn unknown_field_with_alts<'a, T, I>(field: &str, alternates: I) -> Self
121     where
122         T: AsRef<str> + 'a,
123         I: IntoIterator<Item = &'a T>,
124     {
125         Error::new(ErrorUnknownField::with_alts(field, alternates).into())
126     }
127 
128     /// Creates a new error for a field name that appears in the input but does not correspond to
129     /// a known attribute. The second argument is the list of known attributes; if a similar name
130     /// is found that will be shown in the emitted error message.
unknown_field_path_with_alts<'a, T, I>(field: &Path, alternates: I) -> Self where T: AsRef<str> + 'a, I: IntoIterator<Item = &'a T>,131     pub fn unknown_field_path_with_alts<'a, T, I>(field: &Path, alternates: I) -> Self
132     where
133         T: AsRef<str> + 'a,
134         I: IntoIterator<Item = &'a T>,
135     {
136         Error::new(ErrorUnknownField::with_alts(&path_to_string(field), alternates).into())
137     }
138 
139     /// Creates a new error for a struct or variant that does not adhere to the supported shape.
unsupported_shape(shape: &str) -> Self140     pub fn unsupported_shape(shape: &str) -> Self {
141         Error::new(ErrorKind::UnsupportedShape {
142             observed: shape.into(),
143             expected: None,
144         })
145     }
146 
unsupported_shape_with_expected<T: fmt::Display>(shape: &str, expected: &T) -> Self147     pub fn unsupported_shape_with_expected<T: fmt::Display>(shape: &str, expected: &T) -> Self {
148         Error::new(ErrorKind::UnsupportedShape {
149             observed: shape.into(),
150             expected: Some(expected.to_string()),
151         })
152     }
153 
unsupported_format(format: &str) -> Self154     pub fn unsupported_format(format: &str) -> Self {
155         Error::new(ErrorKind::UnexpectedFormat(format.into()))
156     }
157 
158     /// Creates a new error for a field which has an unexpected literal type.
unexpected_type(ty: &str) -> Self159     pub fn unexpected_type(ty: &str) -> Self {
160         Error::new(ErrorKind::UnexpectedType(ty.into()))
161     }
162 
unexpected_expr_type(expr: &Expr) -> Self163     pub fn unexpected_expr_type(expr: &Expr) -> Self {
164         Error::unexpected_type(match *expr {
165             Expr::Array(_) => "array",
166             Expr::Assign(_) => "assign",
167             Expr::Async(_) => "async",
168             Expr::Await(_) => "await",
169             Expr::Binary(_) => "binary",
170             Expr::Block(_) => "block",
171             Expr::Break(_) => "break",
172             Expr::Call(_) => "call",
173             Expr::Cast(_) => "cast",
174             Expr::Closure(_) => "closure",
175             Expr::Const(_) => "const",
176             Expr::Continue(_) => "continue",
177             Expr::Field(_) => "field",
178             Expr::ForLoop(_) => "for_loop",
179             Expr::Group(_) => "group",
180             Expr::If(_) => "if",
181             Expr::Index(_) => "index",
182             Expr::Infer(_) => "infer",
183             Expr::Let(_) => "let",
184             Expr::Lit(_) => "lit",
185             Expr::Loop(_) => "loop",
186             Expr::Macro(_) => "macro",
187             Expr::Match(_) => "match",
188             Expr::MethodCall(_) => "method_call",
189             Expr::Paren(_) => "paren",
190             Expr::Path(_) => "path",
191             Expr::Range(_) => "range",
192             Expr::Reference(_) => "reference",
193             Expr::Repeat(_) => "repeat",
194             Expr::Return(_) => "return",
195             Expr::Struct(_) => "struct",
196             Expr::Try(_) => "try",
197             Expr::TryBlock(_) => "try_block",
198             Expr::Tuple(_) => "tuple",
199             Expr::Unary(_) => "unary",
200             Expr::Unsafe(_) => "unsafe",
201             Expr::Verbatim(_) => "verbatim",
202             Expr::While(_) => "while",
203             Expr::Yield(_) => "yield",
204             // non-exhaustive enum
205             _ => "unknown",
206         })
207         .with_span(expr)
208     }
209 
210     /// Creates a new error for a field which has an unexpected literal type. This will automatically
211     /// extract the literal type name from the passed-in `Lit` and set the span to encompass only the
212     /// literal value.
213     ///
214     /// # Usage
215     /// This is most frequently used in overrides of the `FromMeta::from_value` method.
216     ///
217     /// ```rust
218     /// # // pretend darling_core is darling so the doc example looks correct.
219     /// # extern crate darling_core as darling;
220     /// # extern crate syn;
221     ///
222     /// use darling::{FromMeta, Error, Result};
223     /// use syn::{Lit, LitStr};
224     ///
225     /// pub struct Foo(String);
226     ///
227     /// impl FromMeta for Foo {
228     ///     fn from_value(value: &Lit) -> Result<Self> {
229     ///         if let Lit::Str(ref lit_str) = *value {
230     ///             Ok(Foo(lit_str.value()))
231     ///         } else {
232     ///             Err(Error::unexpected_lit_type(value))
233     ///         }
234     ///     }
235     /// }
236     ///
237     /// # fn main() {}
238     /// ```
unexpected_lit_type(lit: &Lit) -> Self239     pub fn unexpected_lit_type(lit: &Lit) -> Self {
240         Error::unexpected_type(match *lit {
241             Lit::Str(_) => "string",
242             Lit::ByteStr(_) => "byte string",
243             Lit::Byte(_) => "byte",
244             Lit::Char(_) => "char",
245             Lit::Int(_) => "int",
246             Lit::Float(_) => "float",
247             Lit::Bool(_) => "bool",
248             Lit::Verbatim(_) => "verbatim",
249             // non-exhaustive enum
250             _ => "unknown",
251         })
252         .with_span(lit)
253     }
254 
255     /// Creates a new error for a value which doesn't match a set of expected literals.
unknown_value(value: &str) -> Self256     pub fn unknown_value(value: &str) -> Self {
257         Error::new(ErrorKind::UnknownValue(value.into()))
258     }
259 
260     /// Creates a new error for a list which did not get enough items to proceed.
too_few_items(min: usize) -> Self261     pub fn too_few_items(min: usize) -> Self {
262         Error::new(ErrorKind::TooFewItems(min))
263     }
264 
265     /// Creates a new error when a list got more items than it supports. The `max` argument
266     /// is the largest number of items the receiver could accept.
too_many_items(max: usize) -> Self267     pub fn too_many_items(max: usize) -> Self {
268         Error::new(ErrorKind::TooManyItems(max))
269     }
270 
271     /// Bundle a set of multiple errors into a single `Error` instance.
272     ///
273     /// Usually it will be more convenient to use an [`error::Accumulator`](Accumulator).
274     ///
275     /// # Panics
276     /// This function will panic if `errors.is_empty() == true`.
multiple(mut errors: Vec<Error>) -> Self277     pub fn multiple(mut errors: Vec<Error>) -> Self {
278         match errors.len() {
279             1 => errors
280                 .pop()
281                 .expect("Error array of length 1 has a first item"),
282             0 => panic!("Can't deal with 0 errors"),
283             _ => Error::new(ErrorKind::Multiple(errors)),
284         }
285     }
286 
287     /// Creates an error collector, for aggregating multiple errors
288     ///
289     /// See [`Accumulator`] for details.
accumulator() -> Accumulator290     pub fn accumulator() -> Accumulator {
291         Default::default()
292     }
293 }
294 
295 impl Error {
296     /// Create a new error about a literal string that doesn't match a set of known
297     /// or permissible values. This function can be made public if the API proves useful
298     /// beyond impls for `syn` types.
unknown_lit_str_value(value: &LitStr) -> Self299     pub(crate) fn unknown_lit_str_value(value: &LitStr) -> Self {
300         Error::unknown_value(&value.value()).with_span(value)
301     }
302 }
303 
304 /// Error instance methods
305 #[allow(clippy::len_without_is_empty)] // Error can never be empty
306 impl Error {
307     /// Check if this error is associated with a span in the token stream.
has_span(&self) -> bool308     pub fn has_span(&self) -> bool {
309         self.span.is_some()
310     }
311 
312     /// Tie a span to the error if none is already present. This is used in `darling::FromMeta`
313     /// and other traits to attach errors to the most specific possible location in the input
314     /// source code.
315     ///
316     /// All `darling`-built impls, either from the crate or from the proc macro, will call this
317     /// when appropriate during parsing, so it should not be necessary to call this unless you have
318     /// overridden:
319     ///
320     /// * `FromMeta::from_meta`
321     /// * `FromMeta::from_nested_meta`
322     /// * `FromMeta::from_value`
with_span<T: Spanned>(mut self, node: &T) -> Self323     pub fn with_span<T: Spanned>(mut self, node: &T) -> Self {
324         if !self.has_span() {
325             self.span = Some(node.span());
326         }
327 
328         self
329     }
330 
331     /// Get a span for the error.
332     ///
333     /// # Return Value
334     /// This function will return [`Span::call_site()`](proc_macro2::Span) if [`Self::has_span`] is `false`.
335     /// To get the span only if one has been explicitly set for `self`, instead use [`Error::explicit_span`].
span(&self) -> Span336     pub fn span(&self) -> Span {
337         self.span.unwrap_or_else(Span::call_site)
338     }
339 
340     /// Get the span for `self`, if one has been set.
explicit_span(&self) -> Option<Span>341     pub fn explicit_span(&self) -> Option<Span> {
342         self.span
343     }
344 
345     /// Recursively converts a tree of errors to a flattened list.
346     ///
347     /// # Child Diagnostics
348     /// If the `diagnostics` feature is enabled, any child diagnostics on `self`
349     /// will be cloned down to all the errors within `self`.
flatten(self) -> Self350     pub fn flatten(self) -> Self {
351         Error::multiple(self.into_vec())
352     }
353 
into_vec(self) -> Vec<Self>354     fn into_vec(self) -> Vec<Self> {
355         if let ErrorKind::Multiple(errors) = self.kind {
356             let locations = self.locations;
357 
358             #[cfg(feature = "diagnostics")]
359             let children = self.children;
360 
361             errors
362                 .into_iter()
363                 .flat_map(|error| {
364                     // This is mutated if the diagnostics feature is enabled
365                     #[allow(unused_mut)]
366                     let mut error = error.prepend_at(locations.clone());
367 
368                     // Any child diagnostics in `self` are cloned down to all the distinct
369                     // errors contained in `self`.
370                     #[cfg(feature = "diagnostics")]
371                     error.children.extend(children.iter().cloned());
372 
373                     error.into_vec()
374                 })
375                 .collect()
376         } else {
377             vec![self]
378         }
379     }
380 
381     /// Adds a location to the error, such as a field or variant.
382     /// Locations must be added in reverse order of specificity.
at<T: fmt::Display>(mut self, location: T) -> Self383     pub fn at<T: fmt::Display>(mut self, location: T) -> Self {
384         self.locations.insert(0, location.to_string());
385         self
386     }
387 
388     /// Adds a location to the error, such as a field or variant.
389     /// Locations must be added in reverse order of specificity. This is a helper function to avoid
390     /// repeating path to string logic.
at_path(self, path: &Path) -> Self391     pub fn at_path(self, path: &Path) -> Self {
392         self.at(path_to_string(path))
393     }
394 
395     /// Gets the number of individual errors in this error.
396     ///
397     /// This function never returns `0`, as it's impossible to construct
398     /// a multi-error from an empty `Vec`.
len(&self) -> usize399     pub fn len(&self) -> usize {
400         self.kind.len()
401     }
402 
403     /// Consider additional field names as "did you mean" suggestions for
404     /// unknown field errors **if and only if** the caller appears to be operating
405     /// at error's origin (meaning no calls to [`Self::at`] have yet taken place).
406     ///
407     /// # Usage
408     /// `flatten` fields in derived trait implementations rely on this method to offer correct
409     /// "did you mean" suggestions in errors.
410     ///
411     /// Because the `flatten` field receives _all_ unknown fields, if a user mistypes a field name
412     /// that is present on the outer struct but not the flattened struct, they would get an incomplete
413     /// or inferior suggestion unless this method was invoked.
add_sibling_alts_for_unknown_field<'a, T, I>(mut self, alternates: I) -> Self where T: AsRef<str> + 'a, I: IntoIterator<Item = &'a T>,414     pub fn add_sibling_alts_for_unknown_field<'a, T, I>(mut self, alternates: I) -> Self
415     where
416         T: AsRef<str> + 'a,
417         I: IntoIterator<Item = &'a T>,
418     {
419         // The error may have bubbled up before this method was called,
420         // and in those cases adding alternates would be incorrect.
421         if !self.locations.is_empty() {
422             return self;
423         }
424 
425         if let ErrorKind::UnknownField(unknown_field) = &mut self.kind {
426             unknown_field.add_alts(alternates);
427         } else if let ErrorKind::Multiple(errors) = self.kind {
428             let alternates = alternates.into_iter().collect::<Vec<_>>();
429             self.kind = ErrorKind::Multiple(
430                 errors
431                     .into_iter()
432                     .map(|err| {
433                         err.add_sibling_alts_for_unknown_field(
434                             // This clone seems like it shouldn't be necessary.
435                             // Attempting to borrow alternates here leads to the following compiler error:
436                             //
437                             // error: reached the recursion limit while instantiating `darling::Error::add_sibling_alts_for_unknown_field::<'_, &&&&..., ...>`
438                             alternates.clone(),
439                         )
440                     })
441                     .collect(),
442             )
443         }
444 
445         self
446     }
447 
448     /// Adds a location chain to the head of the error's existing locations.
prepend_at(mut self, mut locations: Vec<String>) -> Self449     fn prepend_at(mut self, mut locations: Vec<String>) -> Self {
450         if !locations.is_empty() {
451             locations.extend(self.locations);
452             self.locations = locations;
453         }
454 
455         self
456     }
457 
458     /// Gets the location slice.
459     #[cfg(test)]
location(&self) -> Vec<&str>460     pub(crate) fn location(&self) -> Vec<&str> {
461         self.locations.iter().map(|i| i.as_str()).collect()
462     }
463 
464     /// Write this error and any children as compile errors into a `TokenStream` to
465     /// be returned by the proc-macro.
466     ///
467     /// The behavior of this method will be slightly different if the `diagnostics` feature
468     /// is enabled: In that case, the diagnostics will be emitted immediately by this call,
469     /// and an empty `TokenStream` will be returned.
470     ///
471     /// Return these tokens unmodified to avoid disturbing the attached span information.
472     ///
473     /// # Usage
474     /// ```rust,ignore
475     /// // in your proc-macro function
476     /// let opts = match MyOptions::from_derive_input(&ast) {
477     ///     Ok(val) => val,
478     ///     Err(err) => {
479     ///         return err.write_errors();
480     ///     }
481     /// }
482     /// ```
write_errors(self) -> TokenStream483     pub fn write_errors(self) -> TokenStream {
484         #[cfg(feature = "diagnostics")]
485         {
486             self.emit();
487             TokenStream::default()
488         }
489 
490         #[cfg(not(feature = "diagnostics"))]
491         {
492             syn::Error::from(self).into_compile_error()
493         }
494     }
495 
496     #[cfg(feature = "diagnostics")]
single_to_diagnostic(self) -> ::proc_macro::Diagnostic497     fn single_to_diagnostic(self) -> ::proc_macro::Diagnostic {
498         use proc_macro::{Diagnostic, Level};
499 
500         // Delegate to dedicated error formatters when applicable.
501         //
502         // If span information is available, don't include the error property path
503         // since it's redundant and not consistent with native compiler diagnostics.
504         let diagnostic = match self.kind {
505             ErrorKind::UnknownField(euf) => euf.into_diagnostic(self.span),
506             _ => match self.span {
507                 Some(span) => span.unwrap().error(self.kind.to_string()),
508                 None => Diagnostic::new(Level::Error, self.to_string()),
509             },
510         };
511 
512         self.children
513             .into_iter()
514             .fold(diagnostic, |out, child| child.append_to(out))
515     }
516 
517     /// Transform this error and its children into a list of compiler diagnostics
518     /// and emit them. If the `Error` has associated span information, the diagnostics
519     /// will identify the correct location in source code automatically.
520     ///
521     /// # Stability
522     /// This is only available on `nightly` until the compiler `proc_macro_diagnostic`
523     /// feature stabilizes. Until then, it may break at any time.
524     #[cfg(feature = "diagnostics")]
emit(self)525     pub fn emit(self) {
526         for error in self.flatten() {
527             error.single_to_diagnostic().emit()
528         }
529     }
530 
531     /// Transform the error into a compiler diagnostic and - if the diagnostic points to
532     /// a specific code location - add a spanned help child diagnostic that points to the
533     /// parent derived trait.
534     ///
535     /// This is experimental and therefore not exposed outside the crate.
536     #[cfg(feature = "diagnostics")]
537     #[allow(dead_code)]
emit_with_macro_help_span(self)538     fn emit_with_macro_help_span(self) {
539         use proc_macro::Diagnostic;
540 
541         for error in self.flatten() {
542             let needs_help = error.has_span();
543             let diagnostic = error.single_to_diagnostic();
544             Diagnostic::emit(if needs_help {
545                 diagnostic.span_help(
546                     Span::call_site().unwrap(),
547                     "Encountered as part of this derive-mode-macro",
548                 )
549             } else {
550                 diagnostic
551             })
552         }
553     }
554 }
555 
556 #[cfg(feature = "diagnostics")]
557 macro_rules! add_child {
558     ($unspanned:ident, $spanned:ident, $level:ident) => {
559         #[doc = concat!("Add a child ", stringify!($unspanned), " message to this error.")]
560         #[doc = "# Example"]
561         #[doc = "```rust"]
562         #[doc = "# use darling_core::Error;"]
563         #[doc = concat!(r#"Error::custom("Example")."#, stringify!($unspanned), r#"("message content");"#)]
564         #[doc = "```"]
565         pub fn $unspanned<T: fmt::Display>(mut self, message: T) -> Self {
566             self.children.push(child::ChildDiagnostic::new(
567                 child::Level::$level,
568                 None,
569                 message.to_string(),
570             ));
571             self
572         }
573 
574         #[doc = concat!("Add a child ", stringify!($unspanned), " message to this error with its own span.")]
575         #[doc = "# Example"]
576         #[doc = "```rust"]
577         #[doc = "# use darling_core::Error;"]
578         #[doc = "# let item_to_span = proc_macro2::Span::call_site();"]
579         #[doc = concat!(r#"Error::custom("Example")."#, stringify!($spanned), r#"(&item_to_span, "message content");"#)]
580         #[doc = "```"]
581         pub fn $spanned<S: Spanned, T: fmt::Display>(mut self, span: &S, message: T) -> Self {
582             self.children.push(child::ChildDiagnostic::new(
583                 child::Level::$level,
584                 Some(span.span()),
585                 message.to_string(),
586             ));
587             self
588         }
589     };
590 }
591 
592 /// Add child diagnostics to the error.
593 ///
594 /// # Example
595 ///
596 /// ## Code
597 ///
598 /// ```rust
599 /// # use darling_core::Error;
600 /// # let struct_ident = proc_macro2::Span::call_site();
601 /// Error::custom("this is a demo")
602 ///     .with_span(&struct_ident)
603 ///     .note("we wrote this")
604 ///     .help("try doing this instead");
605 /// ```
606 /// ## Output
607 ///
608 /// ```text
609 /// error: this is a demo
610 ///   --> my_project/my_file.rs:3:5
611 ///    |
612 /// 13 |     FooBar { value: String },
613 ///    |     ^^^^^^
614 ///    |
615 ///    = note: we wrote this
616 ///    = help: try doing this instead
617 /// ```
618 #[cfg(feature = "diagnostics")]
619 impl Error {
620     add_child!(error, span_error, Error);
621     add_child!(warning, span_warning, Warning);
622     add_child!(note, span_note, Note);
623     add_child!(help, span_help, Help);
624 }
625 
626 impl StdError for Error {
description(&self) -> &str627     fn description(&self) -> &str {
628         self.kind.description()
629     }
630 
cause(&self) -> Option<&dyn StdError>631     fn cause(&self) -> Option<&dyn StdError> {
632         None
633     }
634 }
635 
636 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result637     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
638         write!(f, "{}", self.kind)?;
639         if !self.locations.is_empty() {
640             write!(f, " at {}", self.locations.join("/"))?;
641         }
642 
643         Ok(())
644     }
645 }
646 
647 impl From<syn::Error> for Error {
from(e: syn::Error) -> Self648     fn from(e: syn::Error) -> Self {
649         // This impl assumes there is nothing but the message and span that needs to be preserved
650         // from the passed-in error. If this changes at some point, a new ErrorKind should be made
651         // to hold the syn::Error, and this impl should preserve it unmodified while setting its own
652         // span to be a copy of the passed-in error.
653         Self {
654             span: Some(e.span()),
655             ..Self::custom(e)
656         }
657     }
658 }
659 
660 impl From<Error> for syn::Error {
from(e: Error) -> Self661     fn from(e: Error) -> Self {
662         if e.len() == 1 {
663             if let Some(span) = e.explicit_span() {
664                 // Don't include the location path if the error has an explicit span,
665                 // since it will be redundant and isn't consistent with how rustc
666                 // exposes errors.
667                 syn::Error::new(span, e.kind)
668             } else {
669                 // If the error's span is going to be the macro call site, include
670                 // the location information to try and help the user pinpoint the issue.
671                 syn::Error::new(e.span(), e)
672             }
673         } else {
674             let mut syn_errors = e.flatten().into_iter().map(syn::Error::from);
675             let mut error = syn_errors
676                 .next()
677                 .expect("darling::Error can never be empty");
678 
679             for next_error in syn_errors {
680                 error.combine(next_error);
681             }
682 
683             error
684         }
685     }
686 }
687 
688 // Don't want to publicly commit to Error supporting equality yet, but
689 // not having it makes testing very difficult. Note that spans are not
690 // considered for equality since that would break testing in most cases.
691 #[cfg(test)]
692 impl PartialEq for Error {
eq(&self, other: &Self) -> bool693     fn eq(&self, other: &Self) -> bool {
694         self.kind == other.kind && self.locations == other.locations
695     }
696 }
697 
698 #[cfg(test)]
699 impl Eq for Error {}
700 
701 impl IntoIterator for Error {
702     type Item = Error;
703     type IntoIter = IntoIter;
704 
into_iter(self) -> IntoIter705     fn into_iter(self) -> IntoIter {
706         if let ErrorKind::Multiple(errors) = self.kind {
707             IntoIter {
708                 inner: IntoIterEnum::Multiple(errors.into_iter()),
709             }
710         } else {
711             IntoIter {
712                 inner: IntoIterEnum::Single(iter::once(self)),
713             }
714         }
715     }
716 }
717 
718 enum IntoIterEnum {
719     Single(iter::Once<Error>),
720     Multiple(vec::IntoIter<Error>),
721 }
722 
723 impl Iterator for IntoIterEnum {
724     type Item = Error;
725 
next(&mut self) -> Option<Self::Item>726     fn next(&mut self) -> Option<Self::Item> {
727         match *self {
728             IntoIterEnum::Single(ref mut content) => content.next(),
729             IntoIterEnum::Multiple(ref mut content) => content.next(),
730         }
731     }
732 }
733 
734 /// An iterator that moves out of an `Error`.
735 pub struct IntoIter {
736     inner: IntoIterEnum,
737 }
738 
739 impl Iterator for IntoIter {
740     type Item = Error;
741 
next(&mut self) -> Option<Error>742     fn next(&mut self) -> Option<Error> {
743         self.inner.next()
744     }
745 }
746 
747 /// Accumulator for errors, for helping call [`Error::multiple`].
748 ///
749 /// See the docs for [`darling::Error`](Error) for more discussion of error handling with darling.
750 ///
751 /// # Panics
752 ///
753 /// `Accumulator` panics on drop unless [`finish`](Self::finish), [`finish_with`](Self::finish_with),
754 /// or [`into_inner`](Self::into_inner) has been called, **even if it contains no errors**.
755 /// If you want to discard an `Accumulator` that you know to be empty, use `accumulator.finish().unwrap()`.
756 ///
757 /// # Example
758 ///
759 /// ```
760 /// # extern crate darling_core as darling;
761 /// # struct Thing;
762 /// # struct Output;
763 /// # impl Thing { fn validate(self) -> darling::Result<Output> { Ok(Output) } }
764 /// fn validate_things(inputs: Vec<Thing>) -> darling::Result<Vec<Output>> {
765 ///     let mut errors = darling::Error::accumulator();
766 ///
767 ///     let outputs = inputs
768 ///         .into_iter()
769 ///         .filter_map(|thing| errors.handle_in(|| thing.validate()))
770 ///         .collect::<Vec<_>>();
771 ///
772 ///     errors.finish()?;
773 ///     Ok(outputs)
774 /// }
775 /// ```
776 #[derive(Debug)]
777 #[must_use = "Accumulator will panic on drop if not defused."]
778 pub struct Accumulator(Option<Vec<Error>>);
779 
780 impl Accumulator {
781     /// Runs a closure, returning the successful value as `Some`, or collecting the error
782     ///
783     /// The closure's return type is `darling::Result`, so inside it one can use `?`.
handle_in<T, F: FnOnce() -> Result<T>>(&mut self, f: F) -> Option<T>784     pub fn handle_in<T, F: FnOnce() -> Result<T>>(&mut self, f: F) -> Option<T> {
785         self.handle(f())
786     }
787 
788     /// Handles a possible error.
789     ///
790     /// Returns a successful value as `Some`, or collects the error and returns `None`.
handle<T>(&mut self, result: Result<T>) -> Option<T>791     pub fn handle<T>(&mut self, result: Result<T>) -> Option<T> {
792         match result {
793             Ok(y) => Some(y),
794             Err(e) => {
795                 self.push(e);
796                 None
797             }
798         }
799     }
800 
801     /// Stop accumulating errors, producing `Ok` if there are no errors or producing
802     /// an error with all those encountered by the accumulator.
finish(self) -> Result<()>803     pub fn finish(self) -> Result<()> {
804         self.finish_with(())
805     }
806 
807     /// Bundles the collected errors if there were any, or returns the success value
808     ///
809     /// Call this at the end of your input processing.
810     ///
811     /// If there were no errors recorded, returns `Ok(success)`.
812     /// Otherwise calls [`Error::multiple`] and returns the result as an `Err`.
finish_with<T>(self, success: T) -> Result<T>813     pub fn finish_with<T>(self, success: T) -> Result<T> {
814         let errors = self.into_inner();
815         if errors.is_empty() {
816             Ok(success)
817         } else {
818             Err(Error::multiple(errors))
819         }
820     }
821 
errors(&mut self) -> &mut Vec<Error>822     fn errors(&mut self) -> &mut Vec<Error> {
823         match &mut self.0 {
824             Some(errors) => errors,
825             None => panic!("darling internal error: Accumulator accessed after defuse"),
826         }
827     }
828 
829     /// Returns the accumulated errors as a `Vec`.
830     ///
831     /// This function defuses the drop bomb.
832     #[must_use = "Accumulated errors should be handled or propagated to the caller"]
into_inner(mut self) -> Vec<Error>833     pub fn into_inner(mut self) -> Vec<Error> {
834         match self.0.take() {
835             Some(errors) => errors,
836             None => panic!("darling internal error: Accumulator accessed after defuse"),
837         }
838     }
839 
840     /// Add one error to the collection.
push(&mut self, error: Error)841     pub fn push(&mut self, error: Error) {
842         self.errors().push(error)
843     }
844 
845     /// Finish the current accumulation, and if there are no errors create a new `Self` so processing may continue.
846     ///
847     /// This is shorthand for:
848     ///
849     /// ```rust,ignore
850     /// errors.finish()?;
851     /// errors = Error::accumulator();
852     /// ```
853     ///
854     /// # Drop Behavior
855     /// This function returns a new [`Accumulator`] in the success case.
856     /// This new accumulator is "armed" and will detonate if dropped without being finished.
857     ///
858     /// # Example
859     ///
860     /// ```
861     /// # extern crate darling_core as darling;
862     /// # struct Thing;
863     /// # struct Output;
864     /// # impl Thing { fn validate(&self) -> darling::Result<Output> { Ok(Output) } }
865     /// fn validate(lorem_inputs: &[Thing], ipsum_inputs: &[Thing])
866     ///             -> darling::Result<(Vec<Output>, Vec<Output>)> {
867     ///     let mut errors = darling::Error::accumulator();
868     ///
869     ///     let lorems = lorem_inputs.iter().filter_map(|l| {
870     ///         errors.handle(l.validate())
871     ///     }).collect();
872     ///
873     ///     errors = errors.checkpoint()?;
874     ///
875     ///     let ipsums = ipsum_inputs.iter().filter_map(|l| {
876     ///         errors.handle(l.validate())
877     ///     }).collect();
878     ///
879     ///     errors.finish_with((lorems, ipsums))
880     /// }
881     /// # validate(&[], &[]).unwrap();
882     /// ```
checkpoint(self) -> Result<Accumulator>883     pub fn checkpoint(self) -> Result<Accumulator> {
884         // The doc comment says on success we "return the Accumulator for future use".
885         // Actually, we have consumed it by feeding it to finish so we make a fresh one.
886         // This is OK since by definition of the success path, it was empty on entry.
887         self.finish()?;
888         Ok(Self::default())
889     }
890 }
891 
892 impl Default for Accumulator {
default() -> Self893     fn default() -> Self {
894         Accumulator(Some(vec![]))
895     }
896 }
897 
898 impl Extend<Error> for Accumulator {
extend<I>(&mut self, iter: I) where I: IntoIterator<Item = Error>,899     fn extend<I>(&mut self, iter: I)
900     where
901         I: IntoIterator<Item = Error>,
902     {
903         self.errors().extend(iter)
904     }
905 }
906 
907 impl Drop for Accumulator {
drop(&mut self)908     fn drop(&mut self) {
909         // don't try to panic if we are currently unwinding a panic
910         // otherwise we end up with an unhelful "thread panicked while panicking. aborting." message
911         if !std::thread::panicking() {
912             if let Some(errors) = &mut self.0 {
913                 match errors.len() {
914                     0 => panic!("darling::error::Accumulator dropped without being finished"),
915                     error_count => panic!("darling::error::Accumulator dropped without being finished. {} errors were lost.", error_count)
916                 }
917             }
918         }
919     }
920 }
921 
922 #[cfg(test)]
923 mod tests {
924     use super::Error;
925 
926     #[test]
flatten_noop()927     fn flatten_noop() {
928         let err = Error::duplicate_field("hello").at("world");
929         assert_eq!(err.clone().flatten(), err);
930     }
931 
932     #[test]
flatten_simple()933     fn flatten_simple() {
934         let err = Error::multiple(vec![
935             Error::unknown_field("hello").at("world"),
936             Error::missing_field("hell_no").at("world"),
937         ])
938         .at("foo")
939         .flatten();
940 
941         assert!(err.location().is_empty());
942 
943         let mut err_iter = err.into_iter();
944 
945         let first = err_iter.next();
946         assert!(first.is_some());
947         assert_eq!(first.unwrap().location(), vec!["foo", "world"]);
948 
949         let second = err_iter.next();
950         assert!(second.is_some());
951 
952         assert_eq!(second.unwrap().location(), vec!["foo", "world"]);
953 
954         assert!(err_iter.next().is_none());
955     }
956 
957     #[test]
len_single()958     fn len_single() {
959         let err = Error::duplicate_field("hello");
960         assert_eq!(1, err.len());
961     }
962 
963     #[test]
len_multiple()964     fn len_multiple() {
965         let err = Error::multiple(vec![
966             Error::duplicate_field("hello"),
967             Error::missing_field("hell_no"),
968         ]);
969         assert_eq!(2, err.len());
970     }
971 
972     #[test]
len_nested()973     fn len_nested() {
974         let err = Error::multiple(vec![
975             Error::duplicate_field("hello"),
976             Error::multiple(vec![
977                 Error::duplicate_field("hi"),
978                 Error::missing_field("bye"),
979                 Error::multiple(vec![Error::duplicate_field("whatsup")]),
980             ]),
981         ]);
982 
983         assert_eq!(4, err.len());
984     }
985 
986     #[test]
accum_ok()987     fn accum_ok() {
988         let errs = Error::accumulator();
989         assert_eq!("test", errs.finish_with("test").unwrap());
990     }
991 
992     #[test]
accum_errr()993     fn accum_errr() {
994         let mut errs = Error::accumulator();
995         errs.push(Error::custom("foo!"));
996         errs.finish().unwrap_err();
997     }
998 
999     #[test]
accum_into_inner()1000     fn accum_into_inner() {
1001         let mut errs = Error::accumulator();
1002         errs.push(Error::custom("foo!"));
1003         let errs: Vec<_> = errs.into_inner();
1004         assert_eq!(errs.len(), 1);
1005     }
1006 
1007     #[test]
1008     #[should_panic(expected = "Accumulator dropped")]
accum_drop_panic()1009     fn accum_drop_panic() {
1010         let _errs = Error::accumulator();
1011     }
1012 
1013     #[test]
1014     #[should_panic(expected = "2 errors")]
accum_drop_panic_with_error_count()1015     fn accum_drop_panic_with_error_count() {
1016         let mut errors = Error::accumulator();
1017         errors.push(Error::custom("first"));
1018         errors.push(Error::custom("second"));
1019     }
1020 
1021     #[test]
accum_checkpoint_error()1022     fn accum_checkpoint_error() {
1023         let mut errs = Error::accumulator();
1024         errs.push(Error::custom("foo!"));
1025         errs.checkpoint().unwrap_err();
1026     }
1027 
1028     #[test]
1029     #[should_panic(expected = "Accumulator dropped")]
accum_checkpoint_drop_panic()1030     fn accum_checkpoint_drop_panic() {
1031         let mut errs = Error::accumulator();
1032         errs = errs.checkpoint().unwrap();
1033         let _ = errs;
1034     }
1035 }
1036