• 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::iter::FromIterator;
11 use std::slice;
12 use std::vec;
13 
14 /// The result of a Syn parser.
15 pub 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 /// ```
85 pub struct Error {
86     messages: Vec<ErrorMessage>,
87 }
88 
89 struct 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)]
101 struct _Test
102 where
103     Error: Send + Sync;
104 
105 impl 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     /// ```
new<T: Display>(span: Span, message: T) -> Self136     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")]
new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self164     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.
span(&self) -> Span186     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!
to_compile_error(&self) -> TokenStream205     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     /// ```
into_compile_error(self) -> TokenStream244     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.
combine(&mut self, another: Error)250     pub fn combine(&mut self, another: Error) {
251         self.messages.extend(another.messages);
252     }
253 }
254 
255 impl ErrorMessage {
to_compile_error(&self) -> TokenStream256     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")]
new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error288 pub 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")))]
new2<T: Display>(start: Span, end: Span, message: T) -> Error298 pub 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 
312 impl Debug for Error {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result313     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 
328 impl Debug for ErrorMessage {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result329     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
330         Debug::fmt(&self.message, formatter)
331     }
332 }
333 
334 impl Display for Error {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result335     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
336         formatter.write_str(&self.messages[0].message)
337     }
338 }
339 
340 impl Clone for Error {
clone(&self) -> Self341     fn clone(&self) -> Self {
342         Error {
343             messages: self.messages.clone(),
344         }
345     }
346 }
347 
348 impl Clone for ErrorMessage {
clone(&self) -> Self349     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 
364 impl std::error::Error for Error {}
365 
366 impl From<LexError> for Error {
from(err: LexError) -> Self367     fn from(err: LexError) -> Self {
368         Error::new(err.span(), "lex error")
369     }
370 }
371 
372 impl IntoIterator for Error {
373     type Item = Error;
374     type IntoIter = IntoIter;
375 
into_iter(self) -> Self::IntoIter376     fn into_iter(self) -> Self::IntoIter {
377         IntoIter {
378             messages: self.messages.into_iter(),
379         }
380     }
381 }
382 
383 pub struct IntoIter {
384     messages: vec::IntoIter<ErrorMessage>,
385 }
386 
387 impl Iterator for IntoIter {
388     type Item = Error;
389 
next(&mut self) -> Option<Self::Item>390     fn next(&mut self) -> Option<Self::Item> {
391         Some(Error {
392             messages: vec![self.messages.next()?],
393         })
394     }
395 }
396 
397 impl<'a> IntoIterator for &'a Error {
398     type Item = Error;
399     type IntoIter = Iter<'a>;
400 
into_iter(self) -> Self::IntoIter401     fn into_iter(self) -> Self::IntoIter {
402         Iter {
403             messages: self.messages.iter(),
404         }
405     }
406 }
407 
408 pub struct Iter<'a> {
409     messages: slice::Iter<'a, ErrorMessage>,
410 }
411 
412 impl<'a> Iterator for Iter<'a> {
413     type Item = Error;
414 
next(&mut self) -> Option<Self::Item>415     fn next(&mut self) -> Option<Self::Item> {
416         Some(Error {
417             messages: vec![self.messages.next()?.clone()],
418         })
419     }
420 }
421 
422 impl Extend<Error> for Error {
extend<T: IntoIterator<Item = Error>>(&mut self, iter: T)423     fn extend<T: IntoIterator<Item = Error>>(&mut self, iter: T) {
424         for err in iter {
425             self.combine(err);
426         }
427     }
428 }
429