1#![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
31type 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
55enum ErrorTree {
57 Prefix {
59 span: Span,
60 attrs: Vec<Attribute>,
61 nodes: Punctuated<ErrorTree, Token![,]>,
62 },
63 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 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#[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 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
357struct 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 match fields {
710 Fields::Named(named) => {
711 let members = named.named.iter().map(|f| f.ident.as_ref());
712 Ok(quote! {
713 #[allow(unused_variables)]
714 #prefix { #(#members),* } => ::core::iter::empty(),
715 })
716 }
717 Fields::Unnamed(unnamed) => {
718 let params = (0..unnamed.unnamed.len()).map(|i| format_ident!("_{}", i));
719 let args = Self::used_unnamed_fields(label)?;
720 let _ = args;
721 Ok(quote! {
722 #prefix ( #(#params),* ) => ::core::iter::empty(),
723 })
724 }
725 Fields::Unit => Ok(quote! {
726 #prefix => ::core::iter::empty(),
727 }),
728 }
729 }
730 fn additional(&self) -> Result<Vec<TokenStream2>> {
731 self.iter()?
732 .filter_map(|config| {
733 config
734 .map(
735 |Config {
736 msg,
737 ident,
738 fields,
739 label,
740 ..
741 }| { Some((msg, ident?, fields?, label)) },
742 )
743 .transpose()
744 })
745 .map(|config| {
746 let (msg, ident, fields, label) = config?;
747 let label = label.or(msg).ok_or_else(|| {
748 Error::new_spanned(
749 &ident,
750 "Missing label or message. Consider using `#[diag(label = \"...\")]`",
751 )
752 })?;
753 self.additional_branch(&ident, &fields, &label)
754 })
755 .collect()
756 }
757 fn impl_error_enum_branch(
758 &self,
759 ident: &Ident,
760 fields: &Fields,
761 span_field: Option<Ident>,
762 kind: &Kind,
763 number: &str,
764 ) -> Result<Tuple4<TokenStream2>> {
765 let branch_ignored = match fields {
766 Fields::Named(_) => quote! { { .. } },
767 Fields::Unnamed(_) => quote! { (..) },
768 Fields::Unit => quote! {},
769 };
770 let code = format!("{}{}", kind.short_str(), number);
771
772 let prefix = self.variant(ident);
773
774 let kind = quote! {
775 #prefix #branch_ignored => #kind,
776 };
777 let number = quote! {
778 #prefix #branch_ignored => #number,
779 };
780 let code = quote! {
781 #prefix #branch_ignored => #code,
782 };
783 let span_type = self.span_type();
784 let span = if let Some(span_field) = span_field {
785 quote! {::core::option::Option::Some(<#span_type as ::core::convert::From<_>>::from(#span_field))}
786 } else {
787 quote! {::core::option::Option::None}
788 };
789 let primary_span = match fields {
790 Fields::Named(named) => {
791 let members = named.named.iter().map(|f| f.ident.as_ref());
792 quote! {
793 #[allow(unused_variables)]
794 #prefix { #(#members),* } => #span,
795 }
796 }
797 Fields::Unnamed(unnamed) => {
798 let params = (0..unnamed.unnamed.len()).map(|i| format_ident!("_{}", i));
799 quote! {
800 #[allow(unused_variables)]
801 #prefix ( #(#params),* ) => #span,
802 }
803 }
804 Fields::Unit => quote! {
805 #prefix => #span,
806 },
807 };
808 Ok((kind, number, code, primary_span))
809 }
810 fn impl_error_enum(&self) -> Result<Tuple4<Vec<TokenStream2>>> {
811 self.iter()?
812 .filter_map(|config| {
813 config
814 .map(
815 |Config {
816 ident,
817 fields,
818 span_field,
819 kind,
820 number,
821 ..
822 }| {
823 Some((ident?, fields?, span_field, kind, number))
824 },
825 )
826 .transpose()
827 })
828 .map(|config| {
829 let (ident, fields, span_field, kind, number) = config?;
830 let kind = kind.unwrap_or_default();
831 self.impl_error_enum_branch(&ident, &fields, span_field, &kind, &number)
832 })
833 .collect()
834 }
835 fn span_type(&self) -> Cow<'_, Type> {
836 self.config.span_type.as_ref().map_or_else(
837 || {
838 Cow::Owned(parse_quote! {
839 ::error_enum::SimpleSpan
840 })
841 },
842 Cow::Borrowed,
843 )
844 }
845 fn try_to_tokens(&self, tokens: &mut TokenStream2) -> Result<()> {
846 let attrs = &self.attrs;
847 let vis = &self.vis;
848 let name = &self.name;
849 let generics = &self.generics;
850
851 let doc = self.doc()?;
852
853 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
854
855 let variants = self.variants()?;
856
857 if let ErrorEnumInner::Multiple {
858 body: true, brace, ..
859 } = self.inner
860 {
861 tokens.extend(quote! {
862 #(#attrs)*
863 #[doc = "List of error variants:"]
864 #(
865 #[doc = #doc]
866 )*
867 #vis enum #name #generics
868 });
869 brace.surround(tokens, |tokens| {
870 tokens.extend(quote! { #(#variants, )* });
871 });
872 }
873
874 let display = self.display()?;
875 tokens.extend(quote! {
876 impl #impl_generics ::core::fmt::Display for #name #ty_generics #where_clause {
877 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
878 match self {
879 #(#display)*
880 }
881 }
882 }
883 impl #impl_generics ::core::error::Error for #name #ty_generics #where_clause {}
884 });
885
886 let (kind, number, code, primary_span) = self.impl_error_enum()?;
887 let primary_label = self.primary_label()?;
888 let additional = self.additional()?;
889 let span_type = self.span_type();
890 let option_span_type: Type = parse_quote!(::core::option::Option<#span_type>);
891 let msg_type: Type = parse_quote!(::error_enum::String);
892 tokens.extend(quote! {
893 impl #impl_generics ::error_enum::ErrorType for #name #ty_generics #where_clause {
894 type Span = #span_type;
895 type Message = #msg_type;
896
897 fn kind(&self) -> ::error_enum::Kind {
898 match self {
899 #(#kind)*
900 }
901 }
902 fn number(&self) -> &::core::primitive::str {
903 match self {
904 #(#number)*
905 }
906 }
907 fn code(&self) -> &::core::primitive::str {
908 match self {
909 #(#code)*
910 }
911 }
912 fn primary_span(&self) -> #option_span_type {
913 match self {
914 #(#primary_span)*
915 }
916 }
917 fn primary_message(&self) -> #msg_type {
918 ::error_enum::format!("{self}")
919 }
920 fn primary_label(&self) -> #msg_type {
921 match self {
922 #(#primary_label)*
923 }
924 }
925 fn additional(&self) -> impl ::core::iter::Iterator<Item = (#option_span_type, #msg_type, #msg_type)> {
926 match self {
927 #(#additional)*
928 }
929 }
930 }
931 });
932
933 Ok(())
934 }
935}
936
937impl ToTokens for ErrorEnum {
938 fn to_tokens(&self, tokens: &mut TokenStream2) {
939 let mut buffer = TokenStream2::new();
940 self.try_to_tokens(&mut buffer)
941 .inspect(|()| tokens.extend(buffer))
942 .unwrap_or_else(|err| {
943 let diag = err.to_compile_error();
944 tokens.extend(diag);
945 });
946 }
947}
948
949#[doc = include_str!("../attributes.md")]
979#[proc_macro]
980pub fn error_type(token: TokenStream) -> TokenStream {
981 let error = parse_macro_input!(token as ErrorEnum);
982 error.to_token_stream().into()
983}
984
985#[doc = include_str!("../attributes.md")]
988#[proc_macro_derive(ErrorType, attributes(diag))]
989pub fn error_enum(token: TokenStream) -> TokenStream {
990 let input: DeriveInput = parse_macro_input!(token as DeriveInput);
991 let error = ErrorEnum::try_from(input)
992 .map_or_else(|err| err.to_compile_error(), |e| e.to_token_stream());
993 error.into()
994}