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::slice;
11use std::vec;
12
13/// The result of a Syn parser.
14pub 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/// ```
100pub struct Error {
101 messages: Vec<ErrorMessage>,
102}
103
104struct 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.
117struct SpanRange {
118 start: Span,
119 end: Span,
120}
121
122#[cfg(test)]
123struct _Test
124where
125 Error: Send + Sync;
126
127impl 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 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.
209 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!
224 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 /// ```
263 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.
269 pub fn combine(&mut self, another: Error) {
270 self.messages.extend(another.messages);
271 }
272}
273
274impl ErrorMessage {
275 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")]
326pub(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")))]
336pub(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
349impl Debug for Error {
350 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
365impl Debug for ErrorMessage {
366 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
367 Debug::fmt(&self.message, formatter)
368 }
369}
370
371impl Display for Error {
372 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
373 formatter.write_str(&self.messages[0].message)
374 }
375}
376
377impl Clone for Error {
378 fn clone(&self) -> Self {
379 Error {
380 messages: self.messages.clone(),
381 }
382 }
383}
384
385impl Clone for ErrorMessage {
386 fn clone(&self) -> Self {
387 ErrorMessage {
388 span: self.span,
389 message: self.message.clone(),
390 }
391 }
392}
393
394impl Clone for SpanRange {
395 fn clone(&self) -> Self {
396 *self
397 }
398}
399
400impl Copy for SpanRange {}
401
402impl std::error::Error for Error {}
403
404impl From<LexError> for Error {
405 fn from(err: LexError) -> Self {
406 Error::new(err.span(), "lex error")
407 }
408}
409
410impl IntoIterator for Error {
411 type Item = Error;
412 type IntoIter = IntoIter;
413
414 fn into_iter(self) -> Self::IntoIter {
415 IntoIter {
416 messages: self.messages.into_iter(),
417 }
418 }
419}
420
421pub struct IntoIter {
422 messages: vec::IntoIter<ErrorMessage>,
423}
424
425impl Iterator for IntoIter {
426 type Item = Error;
427
428 fn next(&mut self) -> Option<Self::Item> {
429 Some(Error {
430 messages: vec![self.messages.next()?],
431 })
432 }
433}
434
435impl<'a> IntoIterator for &'a Error {
436 type Item = Error;
437 type IntoIter = Iter<'a>;
438
439 fn into_iter(self) -> Self::IntoIter {
440 Iter {
441 messages: self.messages.iter(),
442 }
443 }
444}
445
446pub struct Iter<'a> {
447 messages: slice::Iter<'a, ErrorMessage>,
448}
449
450impl<'a> Iterator for Iter<'a> {
451 type Item = Error;
452
453 fn next(&mut self) -> Option<Self::Item> {
454 Some(Error {
455 messages: vec![self.messages.next()?.clone()],
456 })
457 }
458}
459
460impl Extend<Error> for Error {
461 fn extend<T: IntoIterator<Item = Error>>(&mut self, iter: T) {
462 for err in iter {
463 self.combine(err);
464 }
465 }
466}
467