Skip to main content

error_enum_macros/
lib.rs

1//! # `error-enum-macros`
2//!
3//! A procedural macro crate for [`error-enum`](https://crates.io/crates/error-enum) to define error enums
4//! with rich diagnostics support.
5//!
6//! Please refer to [`error-enum`](https://crates.io/crates/error-enum) and
7//! [`its documentation`](https://docs.rs/error-enum/) for more details.
8#![warn(unused_crate_dependencies)]
9
10use alloc::borrow::Cow;
11use either::Either;
12use lazy_regex::{lazy_regex, Lazy, Regex};
13use proc_macro::TokenStream;
14use proc_macro2::{Span, TokenStream as TokenStream2};
15use quote::{format_ident, quote, ToTokens};
16use syn::{
17    braced,
18    parse::{self, Parse},
19    parse_macro_input, parse_quote,
20    punctuated::{self, Punctuated},
21    token::{self, Brace},
22    Attribute, DeriveInput, Error, Fields, Generics, Ident, LitStr, Result, Token, Type, Variant,
23    Visibility,
24};
25
26extern crate alloc;
27
28#[cfg(test)]
29mod tests;
30
31/// A tuple type with 4 identical types.
32///
33/// For `impl_error_enum_branch` and `impl_error_enum`,
34/// it means `(kind, number, code, primary_span)`.
35type Tuple4<T> = (T, T, T, T);
36
37fn split_fields_attrs(fields: &mut Fields) -> Result<Option<Ident>> {
38    let mut span_ident = None;
39    for (idx, field) in fields.iter_mut().enumerate() {
40        for attr in &field.attrs {
41            if attr.meta.path().is_ident("diag") {
42                attr.parse_nested_meta(|meta| {
43                    if meta.path.is_ident("span") {
44                        span_ident = Some(field.ident.clone().unwrap_or(format_ident!("_{idx}")))
45                    }
46                    Ok(())
47                })?
48            }
49        }
50        field.attrs.retain(|attr| !attr.path().is_ident("diag"));
51    }
52    Ok(span_ident)
53}
54
55/// Tree node of error definitions.
56enum ErrorTree {
57    /// Prefix node.
58    Prefix {
59        span: Span,
60        attrs: Vec<Attribute>,
61        nodes: Punctuated<ErrorTree, Token![,]>,
62    },
63    /// Leaf node.
64    ///
65    /// See [`syn::Variant`] and [`syn::DataStruct`].
66    Variant {
67        span: Span,
68        attrs: Vec<Attribute>,
69        span_ident: Option<Ident>,
70        ident: Ident,
71        fields: Fields,
72    },
73}
74
75impl ErrorTree {
76    fn attrs(&self) -> &[Attribute] {
77        match self {
78            ErrorTree::Prefix { attrs, .. } => attrs,
79            ErrorTree::Variant { attrs, .. } => attrs,
80        }
81    }
82    fn ident(&self) -> Option<&Ident> {
83        match self {
84            ErrorTree::Prefix { .. } => None,
85            ErrorTree::Variant { ident, .. } => Some(ident),
86        }
87    }
88    fn fields(&self) -> Option<&Fields> {
89        match self {
90            ErrorTree::Prefix { .. } => None,
91            ErrorTree::Variant { fields, .. } => Some(fields),
92        }
93    }
94    fn span_ident(&self) -> Option<Ident> {
95        match self {
96            ErrorTree::Prefix { .. } => None,
97            ErrorTree::Variant { span_ident, .. } => span_ident.clone(),
98        }
99    }
100    fn span(&self) -> Span {
101        match self {
102            ErrorTree::Prefix { span, .. } => *span,
103            ErrorTree::Variant { span, .. } => *span,
104        }
105    }
106}
107
108impl Parse for ErrorTree {
109    /// See [`Variant::parse`].
110    fn parse(input: parse::ParseStream) -> syn::Result<Self> {
111        let attrs = input.call(Attribute::parse_outer)?;
112
113        if input.peek(Ident) {
114            let ident: Ident = input.parse()?;
115            let mut fields = if input.peek(token::Brace) {
116                Fields::Named(input.parse()?)
117            } else if input.peek(token::Paren) {
118                Fields::Unnamed(input.parse()?)
119            } else {
120                Fields::Unit
121            };
122            let span_ident = split_fields_attrs(&mut fields)?;
123            Ok(ErrorTree::Variant {
124                span: ident.span(),
125                attrs,
126                span_ident,
127                ident,
128                fields,
129            })
130        } else {
131            let span = input.span();
132            let children;
133            braced!(children in input);
134            let nodes = Punctuated::parse_terminated(&children)?;
135            Ok(ErrorTree::Prefix { span, attrs, nodes })
136        }
137    }
138}
139
140#[derive(Clone, Copy, Default)]
141enum Kind {
142    #[default]
143    Error,
144    Warn,
145}
146
147impl Kind {
148    fn short_str(&self) -> &'static str {
149        match self {
150            Kind::Error => "E",
151            Kind::Warn => "W",
152        }
153    }
154}
155
156impl TryFrom<LitStr> for Kind {
157    type Error = Error;
158
159    fn try_from(value: LitStr) -> Result<Self> {
160        match value.value().as_str() {
161            "error" | "Error" => Ok(Kind::Error),
162            "warn" | "Warn" => Ok(Kind::Warn),
163            _ => Err(Error::new_spanned(
164                value,
165                "Kind must be either `Error` or `Warn`.",
166            )),
167        }
168    }
169}
170
171impl ToTokens for Kind {
172    fn to_tokens(&self, tokens: &mut TokenStream2) {
173        let kind = match self {
174            Kind::Error => quote! { ::error_enum::Kind::Error },
175            Kind::Warn => quote! { ::error_enum::Kind::Warn },
176        };
177        tokens.extend(kind);
178    }
179}
180
181/// Configuration for each variant.
182#[derive(Clone)]
183struct Config {
184    kind: Option<Kind>,
185    number: String,
186    msg: Option<LitStr>,
187    attrs: Vec<Attribute>,
188    ident: Option<Ident>,
189    fields: Option<Fields>,
190    span_field: Option<Ident>,
191    // FIXME: move to `ErrorEnum` for better performance?
192    span_type: Option<Type>,
193    label: Option<LitStr>,
194    depth: usize,
195    nested: bool,
196    #[expect(unused)]
197    span: Span,
198}
199
200impl Config {
201    const fn new(span: Span) -> Self {
202        Self {
203            kind: None,
204            number: String::new(),
205            msg: None,
206            attrs: Vec::new(),
207            ident: None,
208            fields: None,
209            span_field: None,
210            span_type: None,
211            label: None,
212            depth: 0,
213            nested: false,
214            span,
215        }
216    }
217    fn process(
218        &self,
219        attrs: &[Attribute],
220        ident: Option<&Ident>,
221        fields: Option<&Fields>,
222        span_field: Option<Ident>,
223        span: Span,
224    ) -> Result<Self> {
225        let mut kind = self.kind;
226        let mut number = self.number.clone();
227        let mut msg = self.msg.clone();
228        let mut label = self.label.clone();
229        let mut span_type = self.span_type.clone();
230        let depth = self.depth + 1;
231        let mut nested = self.nested;
232        let mut unused_attrs = Vec::new();
233
234        for attr in attrs {
235            if attr.path().is_ident("diag") {
236                attr.parse_nested_meta(|meta| {
237                    if meta.path.is_ident("kind") {
238                        let value: LitStr = meta.value()?.parse()?;
239                        kind = Some(value.try_into()?);
240                    } else if meta.path.is_ident("label") {
241                        let value: LitStr = meta.value()?.parse()?;
242                        label = Some(value);
243                    } else if meta.path.is_ident("msg") {
244                        let value: LitStr = meta.value()?.parse()?;
245                        msg = Some(value);
246                    } else if meta.path.is_ident("nested") {
247                        nested = true;
248                    } else if meta.path.is_ident("number") {
249                        let value: LitStr = meta.value()?.parse()?;
250                        number.push_str(value.value().as_str());
251                    } else if meta.path.is_ident("span_type") {
252                        let value: LitStr = meta.value()?.parse()?;
253                        span_type = Some(value.parse()?);
254                    } else {
255                        return Err(Error::new_spanned(meta.path, "Unknown attribute key."));
256                    }
257                    Ok(())
258                })?
259            } else {
260                unused_attrs.push(attr.clone());
261            }
262        }
263
264        let ident = ident.cloned();
265        let fields = fields.cloned();
266        Ok(Self {
267            kind,
268            number,
269            msg,
270            attrs: unused_attrs,
271            ident,
272            fields,
273            span_field,
274            span_type,
275            label,
276            depth,
277            nested,
278            span,
279        })
280    }
281}
282
283struct ErrorTreeIter<'i> {
284    stack: Vec<(punctuated::Iter<'i, ErrorTree>, Config)>,
285}
286
287impl<'i> ErrorTreeIter<'i> {
288    fn new(tree: punctuated::Iter<'i, ErrorTree>, config: Config) -> Result<Self> {
289        Ok(Self {
290            stack: vec![(tree, config)],
291        })
292    }
293    fn process_next(node: &'i ErrorTree, config: &Config, span: Span) -> Result<Config> {
294        let new_config = config.process(
295            node.attrs(),
296            node.ident(),
297            node.fields(),
298            node.span_ident(),
299            span,
300        )?;
301        Ok(new_config)
302    }
303}
304
305impl<'i> Iterator for ErrorTreeIter<'i> {
306    type Item = Result<Config>;
307
308    fn next(&mut self) -> Option<Self::Item> {
309        while let Some((slice, config)) = self.stack.last_mut() {
310            if let Some(node) = slice.next() {
311                let config = Self::process_next(node, config, node.span())
312                    .map(Some)
313                    .transpose()?;
314                if let Ok(config) = &config {
315                    if let ErrorTree::Prefix { nodes, .. } = node {
316                        self.stack.push((nodes.iter(), config.clone()));
317                    }
318                }
319                return Some(config);
320            } else {
321                self.stack.pop();
322            }
323        }
324        None
325    }
326}
327
328enum ErrorEnumInner {
329    Multiple {
330        brace: Brace,
331        roots: Punctuated<ErrorTree, Token![,]>,
332        body: bool,
333    },
334    Single {
335        node: ErrorTree,
336    },
337}
338
339impl ErrorEnumInner {
340    fn iter(&self, config: Config) -> Result<impl Iterator<Item = Result<Config>> + '_> {
341        match self {
342            ErrorEnumInner::Multiple { roots, .. } => {
343                Ok(Either::Left(ErrorTreeIter::new(roots.iter(), config)?))
344            }
345            ErrorEnumInner::Single { node } => {
346                let iter = Either::Right(core::iter::once(ErrorTreeIter::process_next(
347                    node,
348                    &config,
349                    node.span(),
350                )));
351                Ok(iter)
352            }
353        }
354    }
355}
356
357/// The entire error enum.
358///
359/// ```ignore
360/// pub ErrorName {
361///     // Variants...
362/// }
363/// ```
364struct ErrorEnum {
365    attrs: Vec<Attribute>,
366    vis: Visibility,
367    name: Ident,
368    generics: Generics,
369    inner: ErrorEnumInner,
370    config: Config,
371}
372
373impl ErrorEnum {
374    fn iter(&self) -> Result<impl Iterator<Item = Result<Config>> + '_> {
375        self.inner.iter(self.config.clone())
376    }
377    fn is_enum(&self) -> bool {
378        matches!(self.inner, ErrorEnumInner::Multiple { .. })
379    }
380}
381
382impl Parse for ErrorEnum {
383    fn parse(input: parse::ParseStream) -> syn::Result<Self> {
384        let mut attrs = input.call(Attribute::parse_outer)?;
385        let vis = input.parse()?;
386        let name: Ident = input.parse()?;
387        let generics = input.parse()?;
388        let children;
389        let brace = braced!(children in input);
390        let config = Config::new(name.span()).process(&attrs, None, None, None, name.span())?;
391        attrs.retain(|attr| !attr.path().is_ident("diag"));
392
393        let roots = Punctuated::parse_terminated(&children)?;
394        let inner = ErrorEnumInner::Multiple {
395            body: true,
396            brace,
397            roots,
398        };
399        Ok(Self {
400            attrs,
401            vis,
402            generics,
403            name,
404            inner,
405            config,
406        })
407    }
408}
409
410impl TryFrom<DeriveInput> for ErrorEnum {
411    type Error = Error;
412
413    fn try_from(value: DeriveInput) -> Result<Self> {
414        let DeriveInput {
415            mut attrs,
416            vis,
417            ident,
418            generics,
419            data,
420        } = value;
421        match data {
422            syn::Data::Enum(data_enum) => {
423                let mut roots = Punctuated::new();
424                for pair in data_enum.variants.into_pairs() {
425                    let (mut variant, comma) = pair.into_tuple();
426                    let span = variant.ident.span();
427                    let span_ident = split_fields_attrs(&mut variant.fields)?;
428                    let node = ErrorTree::Variant {
429                        span,
430                        attrs: variant.attrs,
431                        ident: variant.ident,
432                        fields: variant.fields,
433                        span_ident,
434                    };
435                    roots.push_value(node);
436                    if let Some(comma) = comma {
437                        roots.push_punct(comma);
438                    }
439                }
440                let config =
441                    Config::new(ident.span()).process(&attrs, None, None, None, ident.span())?;
442                attrs.retain(|attr| !attr.path().is_ident("diag"));
443
444                let inner = ErrorEnumInner::Multiple {
445                    body: false,
446                    brace: data_enum.brace_token,
447                    roots,
448                };
449                Ok(Self {
450                    attrs,
451                    vis,
452                    name: ident,
453                    generics,
454                    inner,
455                    config,
456                })
457            }
458            syn::Data::Struct(mut data_struct) => {
459                let span = ident.span();
460                let span_ident = split_fields_attrs(&mut data_struct.fields)?;
461                let config =
462                    Config::new(ident.span()).process(&attrs, None, None, None, ident.span())?;
463                attrs.retain(|attr| !attr.path().is_ident("diag"));
464
465                let node = ErrorTree::Variant {
466                    span,
467                    attrs,
468                    ident: ident.clone(),
469                    fields: data_struct.fields,
470                    span_ident,
471                };
472
473                let inner = ErrorEnumInner::Single { node };
474
475                Ok(Self {
476                    attrs: Vec::new(),
477                    vis,
478                    name: ident,
479                    generics,
480                    inner,
481                    config,
482                })
483            }
484            _ => Err(Error::new_spanned(
485                ident,
486                "ErrorEnum can only be derived for enums or structs.",
487            )),
488        }
489    }
490}
491
492impl ErrorEnum {
493    fn variant<'a>(&'a self, ident: &'a Ident) -> impl ToTokens + 'a {
494        struct VariantPrefix<'a> {
495            ident: &'a Ident,
496            is_enum: bool,
497        }
498        impl<'a> ToTokens for VariantPrefix<'a> {
499            fn to_tokens(&self, tokens: &mut TokenStream2) {
500                let ident = self.ident;
501                if self.is_enum {
502                    tokens.extend(quote! { Self::#ident });
503                } else {
504                    tokens.extend(quote! { Self });
505                }
506            }
507        }
508
509        VariantPrefix {
510            ident,
511            is_enum: self.is_enum(),
512        }
513    }
514    fn doc(&self) -> Result<Vec<String>> {
515        self.iter()?
516            .map(|config| {
517                let Config {
518                    number,
519                    depth,
520                    ident,
521                    msg,
522                    kind,
523                    ..
524                } = config?;
525                let indent = "  ".repeat(depth - 2);
526                let msg = msg.as_ref().map(|s| s.value());
527                let kind = kind.unwrap_or_default().short_str();
528                Ok(match (ident, msg) {
529                    (Some(ident), Some(msg)) => {
530                        format!("{indent}- `{kind}{number}`(**{ident}**): {msg}")
531                    }
532                    (None, Some(msg)) => format!("{indent}- `{kind}{number}`: {msg}"),
533                    (Some(ident), None) => format!("{indent}- `{kind}{number}`(**{ident}**)"),
534                    (None, None) => format!("{indent}- `{kind}{number}`"),
535                })
536            })
537            .collect()
538    }
539    fn variants(&self) -> Result<Vec<Variant>> {
540        self.iter()?
541            .filter_map(|config| {
542                config
543                    .map(
544                        |Config {
545                             kind,
546                             msg,
547                             number,
548                             attrs,
549                             ident,
550                             fields,
551                             ..
552                         }| {
553                            Some((kind, msg, number, attrs, ident?, fields?))
554                        },
555                    )
556                    .transpose()
557            })
558            .map(|config| {
559                let (kind, msg, number, mut attrs, ident, fields) = config?;
560
561                let kind = kind.unwrap_or_default();
562                let code = format!("{}{}", kind.short_str(), number);
563
564                let doc = match msg {
565                    Some(msg) => {
566                        format!("`{code}`: {msg}", msg = msg.value())
567                    }
568                    None => format!("`{code}`"),
569                };
570
571                attrs.push(syn::parse_quote! {
572                    #[doc = #doc]
573                });
574                attrs.push(syn::parse_quote! {
575                    #[doc(alias = #code)]
576                });
577
578                Ok(Variant {
579                    attrs,
580                    ident,
581                    fields,
582                    discriminant: None,
583                })
584            })
585            .collect()
586    }
587    fn used_unnamed_fields(msg: &LitStr) -> Result<Vec<Ident>> {
588        static ARG: Lazy<Regex> = lazy_regex!(r#"(^|[^\{])(\{\{)*\{(?<index>\d+)(:[^\{\}]*)?\}"#);
589        ARG.captures_iter(msg.value().as_str())
590            .map(|cap| {
591                let index = cap
592                    .name("index")
593                    .ok_or_else(|| Error::new_spanned(msg, "Invalid argument index."))?
594                    .as_str()
595                    .parse::<usize>()
596                    .map_err(|err| {
597                        Error::new_spanned(msg, format!("Invalid argument index: {err}"))
598                    })?;
599                Ok(format_ident!("_{}", index))
600            })
601            .collect()
602    }
603    fn display_branch(&self, ident: &Ident, fields: &Fields, msg: &LitStr) -> Result<TokenStream2> {
604        let prefix = self.variant(ident);
605        match fields {
606            Fields::Named(named) => {
607                let members = named.named.iter().map(|f| f.ident.as_ref());
608                Ok(quote! {
609                    #[allow(unused_variables)]
610                    #prefix { #(#members),* } => ::core::write!(f, #msg),
611                })
612            }
613            Fields::Unnamed(unnamed) => {
614                let params = (0..unnamed.unnamed.len()).map(|i| format_ident!("_{}", i));
615                let args = Self::used_unnamed_fields(msg)?;
616                Ok(quote! {
617                    #prefix ( #(#params),* ) => ::core::write!(f, #msg #(, #args)* ),
618                })
619            }
620            Fields::Unit => Ok(quote! {
621                #prefix => ::core::write!(f, #msg),
622            }),
623        }
624    }
625    fn display(&self) -> Result<Vec<TokenStream2>> {
626        self.iter()?
627            .filter_map(|config| {
628                config
629                    .map(
630                        |Config {
631                             msg, ident, fields, ..
632                         }| { Some((msg, ident?, fields?)) },
633                    )
634                    .transpose()
635            })
636            .map(|config| {
637                let (msg, ident, fields) = config?;
638                let msg = msg.ok_or_else(|| {
639                    Error::new_spanned(
640                        &ident,
641                        "Missing message. Consider using `#[diag(msg = \"...\")]`",
642                    )
643                })?;
644                self.display_branch(&ident, &fields, &msg)
645            })
646            .collect()
647    }
648    fn primary_label_branch(
649        &self,
650        ident: &Ident,
651        fields: &Fields,
652        label: &LitStr,
653    ) -> Result<TokenStream2> {
654        let prefix = self.variant(ident);
655        match fields {
656            Fields::Named(named) => {
657                let members = named.named.iter().map(|f| f.ident.as_ref());
658                Ok(quote! {
659                    #[allow(unused_variables)]
660                    #prefix { #(#members),* } => ::error_enum::format!(#label),
661                })
662            }
663            Fields::Unnamed(unnamed) => {
664                let params = (0..unnamed.unnamed.len()).map(|i| format_ident!("_{}", i));
665                let args = Self::used_unnamed_fields(label)?;
666                Ok(quote! {
667                    #prefix ( #(#params),* ) => ::error_enum::format!(#label #(, #args)* ),
668                })
669            }
670            Fields::Unit => Ok(quote! {
671                #prefix => ::error_enum::format!(#label),
672            }),
673        }
674    }
675    fn primary_label(&self) -> Result<Vec<TokenStream2>> {
676        self.iter()?
677            .filter_map(|config| {
678                config
679                    .map(
680                        |Config {
681                             msg,
682                             ident,
683                             fields,
684                             label,
685                             ..
686                         }| { Some((msg, ident?, fields?, label)) },
687                    )
688                    .transpose()
689            })
690            .map(|config| {
691                let (msg, ident, fields, label) = config?;
692                let label = label.or(msg).ok_or_else(|| {
693                    Error::new_spanned(
694                        &ident,
695                        "Missing label or message. Consider using `#[diag(label = \"...\")]`",
696                    )
697                })?;
698                self.primary_label_branch(&ident, &fields, &label)
699            })
700            .collect()
701    }
702    fn additional_branch(
703        &self,
704        ident: &Ident,
705        fields: &Fields,
706        label: &LitStr,
707    ) -> Result<TokenStream2> {
708        let prefix = self.variant(ident);
709        let empty_iter: syn::Expr = parse_quote!(::core::iter::empty());
710        let box_type: syn::Expr = parse_quote!(::error_enum::Box);
711        match fields {
712            Fields::Named(named) => {
713                let members = named.named.iter().map(|f| f.ident.as_ref());
714                Ok(quote! {
715                    #[allow(unused_variables)]
716                    #prefix { #(#members),* } => #box_type::new(#empty_iter),
717                })
718            }
719            Fields::Unnamed(unnamed) => {
720                let params = (0..unnamed.unnamed.len()).map(|i| format_ident!("_{}", i));
721                let args = Self::used_unnamed_fields(label)?;
722                let _ = args;
723                Ok(quote! {
724                    #prefix ( #(#params),* ) => #box_type::new(#empty_iter),
725                })
726            }
727            Fields::Unit => Ok(quote! {
728                #prefix => #box_type::new(#empty_iter),
729            }),
730        }
731    }
732    fn additional(&self) -> Result<Vec<TokenStream2>> {
733        self.iter()?
734            .filter_map(|config| {
735                config
736                    .map(
737                        |Config {
738                             msg,
739                             ident,
740                             fields,
741                             label,
742                             ..
743                         }| { Some((msg, ident?, fields?, label)) },
744                    )
745                    .transpose()
746            })
747            .map(|config| {
748                let (msg, ident, fields, label) = config?;
749                let label = label.or(msg).ok_or_else(|| {
750                    Error::new_spanned(
751                        &ident,
752                        "Missing label or message. Consider using `#[diag(label = \"...\")]`",
753                    )
754                })?;
755                self.additional_branch(&ident, &fields, &label)
756            })
757            .collect()
758    }
759    fn impl_error_enum_branch(
760        &self,
761        ident: &Ident,
762        fields: &Fields,
763        span_field: Option<Ident>,
764        kind: &Kind,
765        number: &str,
766    ) -> Result<Tuple4<TokenStream2>> {
767        let branch_ignored = match fields {
768            Fields::Named(_) => quote! { { .. } },
769            Fields::Unnamed(_) => quote! { (..) },
770            Fields::Unit => quote! {},
771        };
772        let code = format!("{}{}", kind.short_str(), number);
773
774        let prefix = self.variant(ident);
775
776        let kind = quote! {
777            #prefix #branch_ignored => #kind,
778        };
779        let number = quote! {
780            #prefix #branch_ignored => #number,
781        };
782        let code = quote! {
783            #prefix #branch_ignored => #code,
784        };
785        let span_type = self.span_type();
786        let span = if let Some(span_field) = span_field {
787            quote! {::core::option::Option::Some(<#span_type as ::core::convert::From<_>>::from(#span_field))}
788        } else {
789            quote! {::core::option::Option::None}
790        };
791        let primary_span = match fields {
792            Fields::Named(named) => {
793                let members = named.named.iter().map(|f| f.ident.as_ref());
794                quote! {
795                    #[allow(unused_variables)]
796                    #prefix { #(#members),* } => #span,
797                }
798            }
799            Fields::Unnamed(unnamed) => {
800                let params = (0..unnamed.unnamed.len()).map(|i| format_ident!("_{}", i));
801                quote! {
802                    #[allow(unused_variables)]
803                    #prefix ( #(#params),* ) => #span,
804                }
805            }
806            Fields::Unit => quote! {
807                #prefix => #span,
808            },
809        };
810        Ok((kind, number, code, primary_span))
811    }
812    fn impl_error_enum(&self) -> Result<Tuple4<Vec<TokenStream2>>> {
813        self.iter()?
814            .filter_map(|config| {
815                config
816                    .map(
817                        |Config {
818                             ident,
819                             fields,
820                             span_field,
821                             kind,
822                             number,
823                             ..
824                         }| {
825                            Some((ident?, fields?, span_field, kind, number))
826                        },
827                    )
828                    .transpose()
829            })
830            .map(|config| {
831                let (ident, fields, span_field, kind, number) = config?;
832                let kind = kind.unwrap_or_default();
833                self.impl_error_enum_branch(&ident, &fields, span_field, &kind, &number)
834            })
835            .collect()
836    }
837    fn span_type(&self) -> Cow<'_, Type> {
838        self.config.span_type.as_ref().map_or_else(
839            || {
840                Cow::Owned(parse_quote! {
841                    ::error_enum::SimpleSpan
842                })
843            },
844            Cow::Borrowed,
845        )
846    }
847    fn try_to_tokens(&self, tokens: &mut TokenStream2) -> Result<()> {
848        let attrs = &self.attrs;
849        let vis = &self.vis;
850        let name = &self.name;
851        let generics = &self.generics;
852
853        let doc = self.doc()?;
854
855        let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
856
857        let variants = self.variants()?;
858
859        if let ErrorEnumInner::Multiple {
860            body: true, brace, ..
861        } = self.inner
862        {
863            tokens.extend(quote! {
864                #(#attrs)*
865                #[doc = "List of error variants:"]
866                #(
867                    #[doc = #doc]
868                )*
869                #vis enum #name #generics
870            });
871            brace.surround(tokens, |tokens| {
872                tokens.extend(quote! { #(#variants, )* });
873            });
874        }
875
876        let display = self.display()?;
877        tokens.extend(quote! {
878            impl #impl_generics ::core::fmt::Display for #name #ty_generics #where_clause {
879                fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
880                    match self {
881                        #(#display)*
882                    }
883                }
884            }
885            impl #impl_generics ::core::error::Error for #name #ty_generics #where_clause {}
886        });
887
888        let (kind, number, code, primary_span) = self.impl_error_enum()?;
889        let primary_label = self.primary_label()?;
890        let additional = self.additional()?;
891        let span_type = self.span_type();
892        let option_span_type: Type = parse_quote!(::core::option::Option<#span_type>);
893        let msg_type: Type = parse_quote!(::error_enum::String);
894        let box_type: Type = parse_quote!(::error_enum::Box);
895        let iterator_trait: Type = parse_quote!(::core::iter::Iterator);
896        tokens.extend(quote! {
897            impl #impl_generics ::error_enum::ErrorType for #name #ty_generics #where_clause {
898                type Span = #span_type;
899                type Message = #msg_type;
900
901                fn kind(&self) -> ::error_enum::Kind {
902                    match self {
903                        #(#kind)*
904                    }
905                }
906                fn number(&self) -> &::core::primitive::str {
907                    match self {
908                        #(#number)*
909                    }
910                }
911                fn code(&self) -> &::core::primitive::str {
912                    match self {
913                        #(#code)*
914                    }
915                }
916                fn primary_span(&self) -> #option_span_type {
917                    match self {
918                        #(#primary_span)*
919                    }
920                }
921                fn primary_message(&self) -> #msg_type {
922                    ::error_enum::format!("{self}")
923                }
924                fn primary_label(&self) -> #msg_type {
925                    match self {
926                        #(#primary_label)*
927                    }
928                }
929                fn additional(&self) -> #box_type<dyn #iterator_trait<Item = (#option_span_type, #msg_type, #msg_type)>> {
930                    match self {
931                        #(#additional)*
932                    }
933                }
934            }
935        });
936
937        Ok(())
938    }
939}
940
941impl ToTokens for ErrorEnum {
942    fn to_tokens(&self, tokens: &mut TokenStream2) {
943        let mut buffer = TokenStream2::new();
944        self.try_to_tokens(&mut buffer)
945            .inspect(|()| tokens.extend(buffer))
946            .unwrap_or_else(|err| {
947                let diag = err.to_compile_error();
948                tokens.extend(diag);
949            });
950    }
951}
952
953/// Define a new layered error type.
954///
955/// # Syntax
956///
957/// ```ignore
958/// $error_type =
959///     $vis:vis $name:ident {
960///         $($variant:variant, )*
961///     }
962///
963/// $variant =
964///   // Prefix node.
965///     {
966///         $($child_variant:variant, )*
967///     }
968///   // Leaf node (three forms, just the same as `syn::Variant`).
969///   | $ident:ident (
970///         $(
971///             $field_ty:ty
972///         ),*
973///     )
974///   | $ident:ident {
975///         $(
976///             $field_name:ident: $field_ty:ty
977///         ),*
978///     }
979///   | $ident:ident
980/// ```
981///
982#[doc = include_str!("../attributes.md")]
983#[proc_macro]
984pub fn error_type(token: TokenStream) -> TokenStream {
985    let error = parse_macro_input!(token as ErrorEnum);
986    error.to_token_stream().into()
987}
988
989/// Implement error capabilities for an existing enum.
990///
991#[doc = include_str!("../attributes.md")]
992#[proc_macro_derive(ErrorType, attributes(diag))]
993pub fn error_enum(token: TokenStream) -> TokenStream {
994    let input: DeriveInput = parse_macro_input!(token as DeriveInput);
995    let error = ErrorEnum::try_from(input)
996        .map_or_else(|err| err.to_compile_error(), |e| e.to_token_stream());
997    error.into()
998}