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