syn/
error.rs

1#[cfg(feature = "parsing")]
2use crate::buffer::Cursor;
3use crate::ext::{PunctExt as _, TokenStreamExt as _};
4use crate::thread::ThreadBound;
5#[cfg(feature = "parsing")]
6use alloc::format;
7use alloc::string::{String, ToString};
8use alloc::vec;
9use alloc::vec::Vec;
10use core::fmt::{self, Debug, Display};
11use core::slice;
12use proc_macro2::{
13    Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
14};
15#[cfg(feature = "printing")]
16use quote::ToTokens;
17
18/// The result of a Syn parser.
19pub type Result<T> = core::result::Result<T, Error>;
20
21/// Error returned when a Syn parser cannot parse the input tokens.
22///
23/// # Error reporting in proc macros
24///
25/// The correct way to report errors back to the compiler from a procedural
26/// macro is by emitting an appropriately spanned invocation of
27/// [`compile_error!`] in the generated code. This produces a better diagnostic
28/// message than simply panicking the macro.
29///
30/// [`compile_error!`]: core::compile_error!
31///
32/// When parsing macro input, the [`parse_macro_input!`] macro handles the
33/// conversion to `compile_error!` automatically.
34///
35/// [`parse_macro_input!`]: crate::parse_macro_input!
36///
37/// ```
38/// # extern crate proc_macro;
39/// #
40/// use proc_macro::TokenStream;
41/// use syn::parse::{Parse, ParseStream, Result};
42/// use syn::{parse_macro_input, ItemFn};
43///
44/// # const IGNORE: &str = stringify! {
45/// #[proc_macro_attribute]
46/// # };
47/// pub fn my_attr(args: TokenStream, input: TokenStream) -> TokenStream {
48///     let args = parse_macro_input!(args as MyAttrArgs);
49///     let input = parse_macro_input!(input as ItemFn);
50///
51///     /* ... */
52///     # TokenStream::new()
53/// }
54///
55/// struct MyAttrArgs {
56///     # _k: [(); { stringify! {
57///     ...
58///     # }; 0 }]
59/// }
60///
61/// impl Parse for MyAttrArgs {
62///     fn parse(input: ParseStream) -> Result<Self> {
63///         # stringify! {
64///         ...
65///         # };
66///         # unimplemented!()
67///     }
68/// }
69/// ```
70///
71/// For errors that arise later than the initial parsing stage, the
72/// [`.to_compile_error()`] or [`.into_compile_error()`] methods can be used to
73/// perform an explicit conversion to `compile_error!`.
74///
75/// [`.to_compile_error()`]: Error::to_compile_error
76/// [`.into_compile_error()`]: Error::into_compile_error
77///
78/// ```
79/// # extern crate proc_macro;
80/// #
81/// # use proc_macro::TokenStream;
82/// # use syn::{parse_macro_input, DeriveInput};
83/// #
84/// # const IGNORE: &str = stringify! {
85/// #[proc_macro_derive(MyDerive)]
86/// # };
87/// pub fn my_derive(input: TokenStream) -> TokenStream {
88///     let input = parse_macro_input!(input as DeriveInput);
89///
90///     // fn(DeriveInput) -> syn::Result<proc_macro2::TokenStream>
91///     expand::my_derive(input)
92///         .unwrap_or_else(syn::Error::into_compile_error)
93///         .into()
94/// }
95/// #
96/// # mod expand {
97/// #     use proc_macro2::TokenStream;
98/// #     use syn::{DeriveInput, Result};
99/// #
100/// #     pub fn my_derive(input: DeriveInput) -> Result<TokenStream> {
101/// #         unimplemented!()
102/// #     }
103/// # }
104/// ```
105pub struct Error {
106    messages: Vec<ErrorMessage>,
107}
108
109struct ErrorMessage {
110    // Span is implemented as an index into a thread-local interner to keep the
111    // size small. It is not safe to access from a different thread. We want
112    // errors to be Send and Sync to play nicely with ecosystem crates for error
113    // handling, so pin the span we're given to its original thread and assume
114    // it is Span::call_site if accessed from any other thread.
115    span: ThreadBound<SpanRange>,
116    message: String,
117}
118
119// Cannot use core::ops::Range<Span> because that does not implement Copy,
120// whereas ThreadBound<T> requires a Copy impl as a way to ensure no Drop impls
121// are involved.
122struct SpanRange {
123    start: Span,
124    end: Span,
125}
126
127#[cfg(test)]
128struct _Test
129where
130    Error: Send + Sync;
131
132impl Error {
133    /// Usually the [`ParseStream::error`] method will be used instead, which
134    /// automatically uses the correct span from the current position of the
135    /// parse stream.
136    ///
137    /// Use `Error::new` when the error needs to be triggered on some span other
138    /// than where the parse stream is currently positioned.
139    ///
140    /// [`ParseStream::error`]: crate::parse::ParseBuffer::error
141    ///
142    /// # Example
143    ///
144    /// ```
145    /// use syn::{Error, Ident, LitStr, Result, Token};
146    /// use syn::parse::ParseStream;
147    ///
148    /// // Parses input that looks like `name = "string"` where the key must be
149    /// // the identifier `name` and the value may be any string literal.
150    /// // Returns the string literal.
151    /// fn parse_name(input: ParseStream) -> Result<LitStr> {
152    ///     let name_token: Ident = input.parse()?;
153    ///     if name_token != "name" {
154    ///         // Trigger an error not on the current position of the stream,
155    ///         // but on the position of the unexpected identifier.
156    ///         return Err(Error::new(name_token.span(), "expected `name`"));
157    ///     }
158    ///     input.parse::<Token![=]>()?;
159    ///     let s: LitStr = input.parse()?;
160    ///     Ok(s)
161    /// }
162    /// ```
163    pub fn new<T: Display>(span: Span, message: T) -> Self {
164        return new(span, message.to_string());
165
166        fn new(span: Span, message: String) -> Error {
167            Error {
168                messages: vec![ErrorMessage {
169                    span: ThreadBound::new(SpanRange {
170                        start: span,
171                        end: span,
172                    }),
173                    message,
174                }],
175            }
176        }
177    }
178
179    /// Creates an error with the specified message spanning the given syntax
180    /// tree node.
181    ///
182    /// Unlike the `Error::new` constructor, this constructor takes an argument
183    /// `tokens` which is a syntax tree node. This allows the resulting `Error`
184    /// to attempt to span all tokens inside of `tokens`. While you would
185    /// typically be able to use the `Spanned` trait with the above `Error::new`
186    /// constructor, implementation limitations today mean that
187    /// `Error::new_spanned` may provide a higher-quality error message on
188    /// stable Rust.
189    ///
190    /// When in doubt it's recommended to stick to `Error::new` (or
191    /// `ParseStream::error`)!
192    #[cfg(feature = "printing")]
193    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
194    pub fn new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self {
195        return new_spanned(tokens.into_token_stream(), message.to_string());
196
197        fn new_spanned(tokens: TokenStream, message: String) -> Error {
198            let mut iter = tokens.into_iter();
199            let start = iter.next().map_or_else(Span::call_site, |t| t.span());
200            let end = iter.last().map_or(start, |t| t.span());
201            Error {
202                messages: vec![ErrorMessage {
203                    span: ThreadBound::new(SpanRange { start, end }),
204                    message,
205                }],
206            }
207        }
208    }
209
210    /// The source location of the error.
211    ///
212    /// Spans are not thread-safe so this function returns `Span::call_site()`
213    /// if called from a different thread than the one on which the `Error` was
214    /// originally created.
215    pub fn span(&self) -> Span {
216        let SpanRange { start, end } = match self.messages[0].span.get() {
217            Some(span) => *span,
218            None => return Span::call_site(),
219        };
220        start.join(end).unwrap_or(start)
221    }
222
223    /// Render the error as an invocation of [`compile_error!`].
224    ///
225    /// The [`parse_macro_input!`] macro provides a convenient way to invoke
226    /// this method correctly in a procedural macro.
227    ///
228    /// [`compile_error!`]: core::compile_error!
229    /// [`parse_macro_input!`]: crate::parse_macro_input!
230    pub fn to_compile_error(&self) -> TokenStream {
231        let mut tokens = TokenStream::new();
232        for msg in &self.messages {
233            ErrorMessage::to_compile_error(msg, &mut tokens);
234        }
235        tokens
236    }
237
238    /// Render the error as an invocation of [`compile_error!`].
239    ///
240    /// [`compile_error!`]: core::compile_error!
241    ///
242    /// # Example
243    ///
244    /// ```
245    /// # extern crate proc_macro;
246    /// #
247    /// use proc_macro::TokenStream;
248    /// use syn::{parse_macro_input, DeriveInput, Error};
249    ///
250    /// # const _: &str = stringify! {
251    /// #[proc_macro_derive(MyTrait)]
252    /// # };
253    /// pub fn derive_my_trait(input: TokenStream) -> TokenStream {
254    ///     let input = parse_macro_input!(input as DeriveInput);
255    ///     my_trait::expand(input)
256    ///         .unwrap_or_else(Error::into_compile_error)
257    ///         .into()
258    /// }
259    ///
260    /// mod my_trait {
261    ///     use proc_macro2::TokenStream;
262    ///     use syn::{DeriveInput, Result};
263    ///
264    ///     pub(crate) fn expand(input: DeriveInput) -> Result<TokenStream> {
265    ///         /* ... */
266    ///         # unimplemented!()
267    ///     }
268    /// }
269    /// ```
270    pub fn into_compile_error(self) -> TokenStream {
271        self.to_compile_error()
272    }
273
274    /// Add another error message to self such that when `to_compile_error()` is
275    /// called, both errors will be emitted together.
276    pub fn combine(&mut self, another: Error) {
277        self.messages.extend(another.messages);
278    }
279}
280
281impl ErrorMessage {
282    fn to_compile_error(&self, tokens: &mut TokenStream) {
283        let (start, end) = match self.span.get() {
284            Some(range) => (range.start, range.end),
285            None => (Span::call_site(), Span::call_site()),
286        };
287
288        // ::core::compile_error!($message)
289        tokens.append(TokenTree::Punct(Punct::new_spanned(
290            ':',
291            Spacing::Joint,
292            start,
293        )));
294        tokens.append(TokenTree::Punct(Punct::new_spanned(
295            ':',
296            Spacing::Alone,
297            start,
298        )));
299        tokens.append(TokenTree::Ident(Ident::new("core", start)));
300        tokens.append(TokenTree::Punct(Punct::new_spanned(
301            ':',
302            Spacing::Joint,
303            start,
304        )));
305        tokens.append(TokenTree::Punct(Punct::new_spanned(
306            ':',
307            Spacing::Alone,
308            start,
309        )));
310        tokens.append(TokenTree::Ident(Ident::new("compile_error", start)));
311        tokens.append(TokenTree::Punct(Punct::new_spanned(
312            '!',
313            Spacing::Alone,
314            start,
315        )));
316        tokens.append(TokenTree::Group({
317            let mut group = Group::new(
318                Delimiter::Brace,
319                TokenStream::from({
320                    let mut string = Literal::string(&self.message);
321                    string.set_span(end);
322                    TokenTree::Literal(string)
323                }),
324            );
325            group.set_span(end);
326            group
327        }));
328    }
329}
330
331#[cfg(feature = "parsing")]
332pub(crate) fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
333    if cursor.eof() {
334        Error::new(scope, format!("unexpected end of input, {}", message))
335    } else {
336        let span = crate::buffer::open_span_of_group(cursor);
337        Error::new(span, message)
338    }
339}
340
341#[cfg(all(feature = "parsing", any(feature = "full", feature = "derive")))]
342pub(crate) fn new2<T: Display>(start: Span, end: Span, message: T) -> Error {
343    return new2(start, end, message.to_string());
344
345    fn new2(start: Span, end: Span, message: String) -> Error {
346        Error {
347            messages: vec![ErrorMessage {
348                span: ThreadBound::new(SpanRange { start, end }),
349                message,
350            }],
351        }
352    }
353}
354
355impl Debug for Error {
356    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
357        if self.messages.len() == 1 {
358            formatter
359                .debug_tuple("Error")
360                .field(&self.messages[0])
361                .finish()
362        } else {
363            formatter
364                .debug_tuple("Error")
365                .field(&self.messages)
366                .finish()
367        }
368    }
369}
370
371impl Debug for ErrorMessage {
372    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
373        Debug::fmt(&self.message, formatter)
374    }
375}
376
377impl Display for Error {
378    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
379        formatter.write_str(&self.messages[0].message)
380    }
381}
382
383impl Clone for Error {
384    fn clone(&self) -> Self {
385        Error {
386            messages: self.messages.clone(),
387        }
388    }
389}
390
391impl Clone for ErrorMessage {
392    fn clone(&self) -> Self {
393        ErrorMessage {
394            span: self.span,
395            message: self.message.clone(),
396        }
397    }
398}
399
400impl Clone for SpanRange {
401    fn clone(&self) -> Self {
402        *self
403    }
404}
405
406impl Copy for SpanRange {}
407
408// TODO: impl core::error::Error (requires Rust 1.81+)
409impl std::error::Error for Error {}
410
411impl From<LexError> for Error {
412    fn from(err: LexError) -> Self {
413        Error::new(err.span(), err)
414    }
415}
416
417impl IntoIterator for Error {
418    type Item = Error;
419    type IntoIter = IntoIter;
420
421    fn into_iter(self) -> Self::IntoIter {
422        IntoIter {
423            messages: self.messages.into_iter(),
424        }
425    }
426}
427
428pub struct IntoIter {
429    messages: vec::IntoIter<ErrorMessage>,
430}
431
432impl Iterator for IntoIter {
433    type Item = Error;
434
435    fn next(&mut self) -> Option<Self::Item> {
436        Some(Error {
437            messages: vec![self.messages.next()?],
438        })
439    }
440}
441
442impl<'a> IntoIterator for &'a Error {
443    type Item = Error;
444    type IntoIter = Iter<'a>;
445
446    fn into_iter(self) -> Self::IntoIter {
447        Iter {
448            messages: self.messages.iter(),
449        }
450    }
451}
452
453pub struct Iter<'a> {
454    messages: slice::Iter<'a, ErrorMessage>,
455}
456
457impl<'a> Iterator for Iter<'a> {
458    type Item = Error;
459
460    fn next(&mut self) -> Option<Self::Item> {
461        Some(Error {
462            messages: vec![self.messages.next()?.clone()],
463        })
464    }
465}
466
467impl Extend<Error> for Error {
468    fn extend<T: IntoIterator<Item = Error>>(&mut self, iter: T) {
469        for err in iter {
470            self.combine(err);
471        }
472    }
473}