syn/
error.rs

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