• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #[cfg(feature = "parsing")]
2 use crate::buffer::Cursor;
3 use crate::thread::ThreadBound;
4 use proc_macro2::{
5     Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
6 };
7 #[cfg(feature = "printing")]
8 use quote::ToTokens;
9 use std::fmt::{self, Debug, Display};
10 use std::slice;
11 use std::vec;
12 
13 /// The result of a Syn parser.
14 pub 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 /// ```
100 pub struct Error {
101     messages: Vec<ErrorMessage>,
102 }
103 
104 struct 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.
117 struct SpanRange {
118     start: Span,
119     end: Span,
120 }
121 
122 #[cfg(test)]
123 struct _Test
124 where
125     Error: Send + Sync;
126 
127 impl 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     /// ```
new<T: Display>(span: Span, message: T) -> Self158     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")]
new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self188     pub fn new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self {
189         return new_spanned(tokens.into_token_stream(), message.to_string());
190 
191         fn new_spanned(tokens: TokenStream, message: String) -> Error {
192             let mut iter = tokens.into_iter();
193             let start = iter.next().map_or_else(Span::call_site, |t| t.span());
194             let end = iter.last().map_or(start, |t| t.span());
195             Error {
196                 messages: vec![ErrorMessage {
197                     span: ThreadBound::new(SpanRange { start, end }),
198                     message,
199                 }],
200             }
201         }
202     }
203 
204     /// The source location of the error.
205     ///
206     /// Spans are not thread-safe so this function returns `Span::call_site()`
207     /// if called from a different thread than the one on which the `Error` was
208     /// originally created.
span(&self) -> Span209     pub fn span(&self) -> Span {
210         let SpanRange { start, end } = match self.messages[0].span.get() {
211             Some(span) => *span,
212             None => return Span::call_site(),
213         };
214         start.join(end).unwrap_or(start)
215     }
216 
217     /// Render the error as an invocation of [`compile_error!`].
218     ///
219     /// The [`parse_macro_input!`] macro provides a convenient way to invoke
220     /// this method correctly in a procedural macro.
221     ///
222     /// [`compile_error!`]: std::compile_error!
223     /// [`parse_macro_input!`]: crate::parse_macro_input!
to_compile_error(&self) -> TokenStream224     pub fn to_compile_error(&self) -> TokenStream {
225         self.messages
226             .iter()
227             .map(ErrorMessage::to_compile_error)
228             .collect()
229     }
230 
231     /// Render the error as an invocation of [`compile_error!`].
232     ///
233     /// [`compile_error!`]: std::compile_error!
234     ///
235     /// # Example
236     ///
237     /// ```
238     /// # extern crate proc_macro;
239     /// #
240     /// use proc_macro::TokenStream;
241     /// use syn::{parse_macro_input, DeriveInput, Error};
242     ///
243     /// # const _: &str = stringify! {
244     /// #[proc_macro_derive(MyTrait)]
245     /// # };
246     /// pub fn derive_my_trait(input: TokenStream) -> TokenStream {
247     ///     let input = parse_macro_input!(input as DeriveInput);
248     ///     my_trait::expand(input)
249     ///         .unwrap_or_else(Error::into_compile_error)
250     ///         .into()
251     /// }
252     ///
253     /// mod my_trait {
254     ///     use proc_macro2::TokenStream;
255     ///     use syn::{DeriveInput, Result};
256     ///
257     ///     pub(crate) fn expand(input: DeriveInput) -> Result<TokenStream> {
258     ///         /* ... */
259     ///         # unimplemented!()
260     ///     }
261     /// }
262     /// ```
into_compile_error(self) -> TokenStream263     pub fn into_compile_error(self) -> TokenStream {
264         self.to_compile_error()
265     }
266 
267     /// Add another error message to self such that when `to_compile_error()` is
268     /// called, both errors will be emitted together.
combine(&mut self, another: Error)269     pub fn combine(&mut self, another: Error) {
270         self.messages.extend(another.messages);
271     }
272 }
273 
274 impl ErrorMessage {
to_compile_error(&self) -> TokenStream275     fn to_compile_error(&self) -> TokenStream {
276         let (start, end) = match self.span.get() {
277             Some(range) => (range.start, range.end),
278             None => (Span::call_site(), Span::call_site()),
279         };
280 
281         // ::core::compile_error!($message)
282         TokenStream::from_iter(vec![
283             TokenTree::Punct({
284                 let mut punct = Punct::new(':', Spacing::Joint);
285                 punct.set_span(start);
286                 punct
287             }),
288             TokenTree::Punct({
289                 let mut punct = Punct::new(':', Spacing::Alone);
290                 punct.set_span(start);
291                 punct
292             }),
293             TokenTree::Ident(Ident::new("core", start)),
294             TokenTree::Punct({
295                 let mut punct = Punct::new(':', Spacing::Joint);
296                 punct.set_span(start);
297                 punct
298             }),
299             TokenTree::Punct({
300                 let mut punct = Punct::new(':', Spacing::Alone);
301                 punct.set_span(start);
302                 punct
303             }),
304             TokenTree::Ident(Ident::new("compile_error", start)),
305             TokenTree::Punct({
306                 let mut punct = Punct::new('!', Spacing::Alone);
307                 punct.set_span(start);
308                 punct
309             }),
310             TokenTree::Group({
311                 let mut group = Group::new(Delimiter::Brace, {
312                     TokenStream::from_iter(vec![TokenTree::Literal({
313                         let mut string = Literal::string(&self.message);
314                         string.set_span(end);
315                         string
316                     })])
317                 });
318                 group.set_span(end);
319                 group
320             }),
321         ])
322     }
323 }
324 
325 #[cfg(feature = "parsing")]
new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error326 pub(crate) fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
327     if cursor.eof() {
328         Error::new(scope, format!("unexpected end of input, {}", message))
329     } else {
330         let span = crate::buffer::open_span_of_group(cursor);
331         Error::new(span, message)
332     }
333 }
334 
335 #[cfg(all(feature = "parsing", any(feature = "full", feature = "derive")))]
new2<T: Display>(start: Span, end: Span, message: T) -> Error336 pub(crate) fn new2<T: Display>(start: Span, end: Span, message: T) -> Error {
337     return new2(start, end, message.to_string());
338 
339     fn new2(start: Span, end: Span, message: String) -> Error {
340         Error {
341             messages: vec![ErrorMessage {
342                 span: ThreadBound::new(SpanRange { start, end }),
343                 message,
344             }],
345         }
346     }
347 }
348 
349 impl Debug for Error {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result350     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
351         if self.messages.len() == 1 {
352             formatter
353                 .debug_tuple("Error")
354                 .field(&self.messages[0])
355                 .finish()
356         } else {
357             formatter
358                 .debug_tuple("Error")
359                 .field(&self.messages)
360                 .finish()
361         }
362     }
363 }
364 
365 impl Debug for ErrorMessage {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result366     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
367         Debug::fmt(&self.message, formatter)
368     }
369 }
370 
371 impl Display for Error {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result372     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
373         formatter.write_str(&self.messages[0].message)
374     }
375 }
376 
377 impl Clone for Error {
clone(&self) -> Self378     fn clone(&self) -> Self {
379         Error {
380             messages: self.messages.clone(),
381         }
382     }
383 }
384 
385 impl Clone for ErrorMessage {
clone(&self) -> Self386     fn clone(&self) -> Self {
387         ErrorMessage {
388             span: self.span,
389             message: self.message.clone(),
390         }
391     }
392 }
393 
394 impl Clone for SpanRange {
clone(&self) -> Self395     fn clone(&self) -> Self {
396         *self
397     }
398 }
399 
400 impl Copy for SpanRange {}
401 
402 impl std::error::Error for Error {}
403 
404 impl From<LexError> for Error {
from(err: LexError) -> Self405     fn from(err: LexError) -> Self {
406         Error::new(err.span(), "lex error")
407     }
408 }
409 
410 impl IntoIterator for Error {
411     type Item = Error;
412     type IntoIter = IntoIter;
413 
into_iter(self) -> Self::IntoIter414     fn into_iter(self) -> Self::IntoIter {
415         IntoIter {
416             messages: self.messages.into_iter(),
417         }
418     }
419 }
420 
421 pub struct IntoIter {
422     messages: vec::IntoIter<ErrorMessage>,
423 }
424 
425 impl Iterator for IntoIter {
426     type Item = Error;
427 
next(&mut self) -> Option<Self::Item>428     fn next(&mut self) -> Option<Self::Item> {
429         Some(Error {
430             messages: vec![self.messages.next()?],
431         })
432     }
433 }
434 
435 impl<'a> IntoIterator for &'a Error {
436     type Item = Error;
437     type IntoIter = Iter<'a>;
438 
into_iter(self) -> Self::IntoIter439     fn into_iter(self) -> Self::IntoIter {
440         Iter {
441             messages: self.messages.iter(),
442         }
443     }
444 }
445 
446 pub struct Iter<'a> {
447     messages: slice::Iter<'a, ErrorMessage>,
448 }
449 
450 impl<'a> Iterator for Iter<'a> {
451     type Item = Error;
452 
next(&mut self) -> Option<Self::Item>453     fn next(&mut self) -> Option<Self::Item> {
454         Some(Error {
455             messages: vec![self.messages.next()?.clone()],
456         })
457     }
458 }
459 
460 impl Extend<Error> for Error {
extend<T: IntoIterator<Item = Error>>(&mut self, iter: T)461     fn extend<T: IntoIterator<Item = Error>>(&mut self, iter: T) {
462         for err in iter {
463             self.combine(err);
464         }
465     }
466 }
467