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")]
188 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self189 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.
span(&self) -> Span210 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!
to_compile_error(&self) -> TokenStream225 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 /// ```
into_compile_error(self) -> TokenStream264 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.
combine(&mut self, another: Error)270 pub fn combine(&mut self, another: Error) {
271 self.messages.extend(another.messages);
272 }
273 }
274
275 impl ErrorMessage {
to_compile_error(&self) -> TokenStream276 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")]
new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error327 pub(crate) fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
328 if cursor.eof() {
329 Error::new(scope, format!("unexpected end of input, {}", message))
330 } else {
331 let 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")))]
new2<T: Display>(start: Span, end: Span, message: T) -> Error337 pub(crate) fn new2<T: Display>(start: Span, end: Span, message: T) -> Error {
338 return new2(start, end, 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 {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result351 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
352 if self.messages.len() == 1 {
353 formatter
354 .debug_tuple("Error")
355 .field(&self.messages[0])
356 .finish()
357 } else {
358 formatter
359 .debug_tuple("Error")
360 .field(&self.messages)
361 .finish()
362 }
363 }
364 }
365
366 impl Debug for ErrorMessage {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result367 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
368 Debug::fmt(&self.message, formatter)
369 }
370 }
371
372 impl Display for Error {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result373 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 {
clone(&self) -> Self379 fn clone(&self) -> Self {
380 Error {
381 messages: self.messages.clone(),
382 }
383 }
384 }
385
386 impl Clone for ErrorMessage {
clone(&self) -> Self387 fn clone(&self) -> Self {
388 ErrorMessage {
389 span: self.span,
390 message: self.message.clone(),
391 }
392 }
393 }
394
395 impl Clone for SpanRange {
clone(&self) -> Self396 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 {
from(err: LexError) -> Self406 fn from(err: LexError) -> Self {
407 Error::new(err.span(), err)
408 }
409 }
410
411 impl IntoIterator for Error {
412 type Item = Error;
413 type IntoIter = IntoIter;
414
into_iter(self) -> Self::IntoIter415 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
next(&mut self) -> Option<Self::Item>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
into_iter(self) -> Self::IntoIter440 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
next(&mut self) -> Option<Self::Item>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 {
extend<T: IntoIterator<Item = Error>>(&mut self, iter: T)462 fn extend<T: IntoIterator<Item = Error>>(&mut self, iter: T) {
463 for err in iter {
464 self.combine(err);
465 }
466 }
467 }
468