syn/
error.rs

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