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 | /// ``` |
136 | 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" )] |
164 | 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. |
186 | 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! |
205 | 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 | /// ``` |
244 | 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. |
250 | pub fn combine(&mut self, another: Error) { |
251 | self.messages.extend(another.messages); |
252 | } |
253 | } |
254 | |
255 | impl ErrorMessage { |
256 | 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" )] |
288 | 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" )))] |
298 | 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 { |
313 | 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 { |
329 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
330 | Debug::fmt(&self.message, formatter) |
331 | } |
332 | } |
333 | |
334 | impl Display for Error { |
335 | 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 { |
341 | fn clone(&self) -> Self { |
342 | Error { |
343 | messages: self.messages.clone(), |
344 | } |
345 | } |
346 | } |
347 | |
348 | impl Clone for ErrorMessage { |
349 | 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 { |
367 | 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 | |
376 | 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 | |
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 | |
401 | 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 | |
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 { |
423 | fn extend<T: IntoIterator<Item = Error>>(&mut self, iter: T) { |
424 | for err in iter { |
425 | self.combine(err); |
426 | } |
427 | } |
428 | } |
429 | |