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 | /// ``` |
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 (doc_cfg, 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 | |
275 | impl 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(vec![ |
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(vec![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" )] |
327 | pub(crate) fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error { |
328 | if cursor.eof() { |
329 | Error::new(span:scope, message:format!("unexpected end of input, {}" , message)) |
330 | } else { |
331 | let span: 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" )))] |
337 | pub(crate) fn new2<T: Display>(start: Span, end: Span, message: T) -> Error { |
338 | return new2(start, end, message: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 | |
350 | impl Debug for Error { |
351 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
352 | if self.messages.len() == 1 { |
353 | formatter&mut DebugTuple<'_, '_> |
354 | .debug_tuple(name:"Error" ) |
355 | .field(&self.messages[0]) |
356 | .finish() |
357 | } else { |
358 | formatter&mut DebugTuple<'_, '_> |
359 | .debug_tuple(name:"Error" ) |
360 | .field(&self.messages) |
361 | .finish() |
362 | } |
363 | } |
364 | } |
365 | |
366 | impl Debug for ErrorMessage { |
367 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
368 | Debug::fmt(&self.message, f:formatter) |
369 | } |
370 | } |
371 | |
372 | impl Display for Error { |
373 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
374 | formatter.write_str(&self.messages[0].message) |
375 | } |
376 | } |
377 | |
378 | impl Clone for Error { |
379 | fn clone(&self) -> Self { |
380 | Error { |
381 | messages: self.messages.clone(), |
382 | } |
383 | } |
384 | } |
385 | |
386 | impl Clone for ErrorMessage { |
387 | fn clone(&self) -> Self { |
388 | ErrorMessage { |
389 | span: self.span, |
390 | message: self.message.clone(), |
391 | } |
392 | } |
393 | } |
394 | |
395 | impl Clone for SpanRange { |
396 | fn clone(&self) -> Self { |
397 | *self |
398 | } |
399 | } |
400 | |
401 | impl Copy for SpanRange {} |
402 | |
403 | impl std::error::Error for Error {} |
404 | |
405 | impl From<LexError> for Error { |
406 | fn from(err: LexError) -> Self { |
407 | Error::new(err.span(), message:err) |
408 | } |
409 | } |
410 | |
411 | impl 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 | |
422 | pub struct IntoIter { |
423 | messages: vec::IntoIter<ErrorMessage>, |
424 | } |
425 | |
426 | impl 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 | |
436 | impl<'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 | |
447 | pub struct Iter<'a> { |
448 | messages: slice::Iter<'a, ErrorMessage>, |
449 | } |
450 | |
451 | impl<'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 | |
461 | impl Extend<Error> for Error { |
462 | fn extend<T: IntoIterator<Item = Error>>(&mut self, iter: T) { |
463 | for err: Error in iter { |
464 | self.combine(another:err); |
465 | } |
466 | } |
467 | } |
468 | |