1#[cfg(feature = "parsing")]
2use crate::buffer::Cursor;
3use crate::thread::ThreadBound;
4use proc_macro2::{
5 Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
6};
7#[cfg(feature = "printing")]
8use quote::ToTokens;
9use std::fmt::{self, Debug, Display};
10use std::iter::FromIterator;
11use std::slice;
12use std::vec;
13
14/// The result of a Syn parser.
15pub 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/// ```
85pub struct Error {
86 messages: Vec<ErrorMessage>,
87}
88
89struct 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)]
101struct _Test
102where
103 Error: Send + Sync;
104
105impl 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
255impl 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")]
288pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
289 if cursor.eof() {
290 Error::new(span:scope, message:format!("unexpected end of input, {}", message))
291 } else {
292 let span: 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")))]
298pub fn new2<T: Display>(start: Span, end: Span, message: T) -> Error {
299 return new2(start, end, message: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
312impl Debug for Error {
313 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
314 if self.messages.len() == 1 {
315 formatter&mut DebugTuple<'_, '_>
316 .debug_tuple(name:"Error")
317 .field(&self.messages[0])
318 .finish()
319 } else {
320 formatter&mut DebugTuple<'_, '_>
321 .debug_tuple(name:"Error")
322 .field(&self.messages)
323 .finish()
324 }
325 }
326}
327
328impl Debug for ErrorMessage {
329 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
330 Debug::fmt(&self.message, f:formatter)
331 }
332}
333
334impl Display for Error {
335 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
336 formatter.write_str(&self.messages[0].message)
337 }
338}
339
340impl Clone for Error {
341 fn clone(&self) -> Self {
342 Error {
343 messages: self.messages.clone(),
344 }
345 }
346}
347
348impl Clone for ErrorMessage {
349 fn clone(&self) -> Self {
350 let start: Span = self
351 .start_span
352 .get()
353 .cloned()
354 .unwrap_or_else(Span::call_site);
355 let end: Span = 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
364impl std::error::Error for Error {}
365
366impl From<LexError> for Error {
367 fn from(err: LexError) -> Self {
368 Error::new(err.span(), message:"lex error")
369 }
370}
371
372impl 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
383pub struct IntoIter {
384 messages: vec::IntoIter<ErrorMessage>,
385}
386
387impl 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
397impl<'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
408pub struct Iter<'a> {
409 messages: slice::Iter<'a, ErrorMessage>,
410}
411
412impl<'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
422impl Extend<Error> for Error {
423 fn extend<T: IntoIterator<Item = Error>>(&mut self, iter: T) {
424 for err: Error in iter {
425 self.combine(another:err);
426 }
427 }
428}
429