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