From 60bd6a92d3a599448cd7fa71ba0b0e094633941b Mon Sep 17 00:00:00 2001 From: Schneems Date: Tue, 1 Apr 2025 12:52:58 -0500 Subject: [PATCH] Add syn::Error::combine examples to docs We should encourage macro authors to emit as many errors as possible at once. This functionality is already present in syn::Error, but it was not immediately clear. I wanted to add some documentation that could have helped me better use the syn::Error::combine functionality. For some more background https://www.schneems.com/2025/03/26/a-daft-procmacro-trick-how-to-emit-partialcode-errors/. This commit adds two examples, one shows accumulating "maybe errors" with the aid of VecDeque, and the second shows iterating over the result of combined errors and calls out that this is helpful for unit testing. --- src/error.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/src/error.rs b/src/error.rs index 63310543a3..f053ebe2c1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -265,8 +265,56 @@ impl Error { self.to_compile_error() } - /// Add another error message to self such that when `to_compile_error()` is - /// called, both errors will be emitted together. + /// Combine multiple errors into a single [`syn::Error`] + /// + /// Adds the error to self so that when `to_compile_error()` is called, + /// all errors will be emitted together. Accumulating and emitting many + /// errors at once helps developer tools highlight multiple problems that + /// need to be fixed instead of just the first problem. + /// + /// To hold zero or more errors, you can collect them in a [`std::collections::VecDeque`] + /// and convert them into a single [`syn::Error`] using [`syn::Error::combine`]. + /// For example: + /// + /// ```rust + /// use std::collections::VecDeque; + /// use syn::parse::{Parse, ParseStream}; + /// + /// fn parse_attrs(attrs: &[syn::Attribute]) -> Result, syn::Error> + /// where + /// T: Parse + /// { + /// let mut errors: VecDeque = VecDeque::new(); + /// + /// // Logic that may error ... + /// + /// if let Some(mut error) = errors.pop_front() { + /// for e in errors { + /// error.combine(e); + /// } + /// Err(error) + /// } else { + /// # let out = todo!(); + /// Ok(out) + /// } + /// } + /// ``` + /// + /// Errors can be iterated over once combined. This capability helps + /// unit testing multiple errors. For example: + /// + /// ```rust + /// # use proc_macro2::Span; + /// # let span = Span::call_site(); + /// + /// let mut error = syn::Error::new(span, "first error"); + /// error.combine(syn::Error::new(span, "second error")); + /// + /// assert_eq!( + /// vec!["first error".to_string(), "second error".to_string()], + /// error.into_iter().map(|x| x.to_string()).collect::>() + /// ) + /// ``` pub fn combine(&mut self, another: Error) { self.messages.extend(another.messages); }