• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std;
2 use std::fmt::{self, Debug, Display};
3 use std::iter::FromIterator;
4 use std::slice;
5 use std::vec;
6 
7 use proc_macro2::{
8     Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
9 };
10 #[cfg(feature = "printing")]
11 use quote::ToTokens;
12 
13 #[cfg(feature = "parsing")]
14 use crate::buffer::Cursor;
15 use crate::thread::ThreadBound;
16 
17 /// The result of a Syn parser.
18 pub 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)]
86 pub struct Error {
87     messages: Vec<ErrorMessage>,
88 }
89 
90 struct 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)]
102 struct _Test
103 where
104     Error: Send + Sync;
105 
106 impl 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     /// ```
new<T: Display>(span: Span, message: T) -> Self137     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")]
new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self161     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.
span(&self) -> Span179     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
to_compile_error(&self) -> TokenStream197     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.
combine(&mut self, another: Error)206     pub fn combine(&mut self, another: Error) {
207         self.messages.extend(another.messages)
208     }
209 }
210 
211 impl ErrorMessage {
to_compile_error(&self) -> TokenStream212     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")]
new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error244 pub 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 
253 impl Debug for Error {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result254     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 
269 impl Debug for ErrorMessage {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result270     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
271         Debug::fmt(&self.message, formatter)
272     }
273 }
274 
275 impl Display for Error {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result276     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
277         formatter.write_str(&self.messages[0].message)
278     }
279 }
280 
281 impl Clone for ErrorMessage {
clone(&self) -> Self282     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 
297 impl std::error::Error for Error {
description(&self) -> &str298     fn description(&self) -> &str {
299         "parse error"
300     }
301 }
302 
303 impl From<LexError> for Error {
from(err: LexError) -> Self304     fn from(err: LexError) -> Self {
305         Error::new(Span::call_site(), format!("{:?}", err))
306     }
307 }
308 
309 impl IntoIterator for Error {
310     type Item = Error;
311     type IntoIter = IntoIter;
312 
into_iter(self) -> Self::IntoIter313     fn into_iter(self) -> Self::IntoIter {
314         IntoIter {
315             messages: self.messages.into_iter(),
316         }
317     }
318 }
319 
320 pub struct IntoIter {
321     messages: vec::IntoIter<ErrorMessage>,
322 }
323 
324 impl Iterator for IntoIter {
325     type Item = Error;
326 
next(&mut self) -> Option<Self::Item>327     fn next(&mut self) -> Option<Self::Item> {
328         Some(Error {
329             messages: vec![self.messages.next()?],
330         })
331     }
332 }
333 
334 impl<'a> IntoIterator for &'a Error {
335     type Item = Error;
336     type IntoIter = Iter<'a>;
337 
into_iter(self) -> Self::IntoIter338     fn into_iter(self) -> Self::IntoIter {
339         Iter {
340             messages: self.messages.iter(),
341         }
342     }
343 }
344 
345 pub struct Iter<'a> {
346     messages: slice::Iter<'a, ErrorMessage>,
347 }
348 
349 impl<'a> Iterator for Iter<'a> {
350     type Item = Error;
351 
next(&mut self) -> Option<Self::Item>352     fn next(&mut self) -> Option<Self::Item> {
353         Some(Error {
354             messages: vec![self.messages.next()?.clone()],
355         })
356     }
357 }
358