1 use std;
2 use std::fmt::{self, Debug, Display};
3 use std::iter::FromIterator;
4 use std::slice;
5 use std::vec;
6
7 use proc_macro2::{
8 Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
9 };
10 #[cfg(feature = "printing")]
11 use quote::ToTokens;
12
13 #[cfg(feature = "parsing")]
14 use crate::buffer::Cursor;
15 use crate::thread::ThreadBound;
16
17 /// The result of a Syn parser.
18 pub type Result<T> = std::result::Result<T, Error>;
19
20 /// Error returned when a Syn parser cannot parse the input tokens.
21 ///
22 /// # Error reporting in proc macros
23 ///
24 /// The correct way to report errors back to the compiler from a procedural
25 /// macro is by emitting an appropriately spanned invocation of
26 /// [`compile_error!`] in the generated code. This produces a better diagnostic
27 /// message than simply panicking the macro.
28 ///
29 /// [`compile_error!`]: https://doc.rust-lang.org/std/macro.compile_error.html
30 ///
31 /// When parsing macro input, the [`parse_macro_input!`] macro handles the
32 /// conversion to `compile_error!` automatically.
33 ///
34 /// ```
35 /// extern crate proc_macro;
36 ///
37 /// use proc_macro::TokenStream;
38 /// use syn::{parse_macro_input, AttributeArgs, ItemFn};
39 ///
40 /// # const IGNORE: &str = stringify! {
41 /// #[proc_macro_attribute]
42 /// # };
43 /// pub fn my_attr(args: TokenStream, input: TokenStream) -> TokenStream {
44 /// let args = parse_macro_input!(args as AttributeArgs);
45 /// let input = parse_macro_input!(input as ItemFn);
46 ///
47 /// /* ... */
48 /// # TokenStream::new()
49 /// }
50 /// ```
51 ///
52 /// For errors that arise later than the initial parsing stage, the
53 /// [`.to_compile_error()`] method can be used to perform an explicit conversion
54 /// to `compile_error!`.
55 ///
56 /// [`.to_compile_error()`]: Error::to_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(|err| err.to_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 /// ```
85 #[derive(Clone)]
86 pub struct Error {
87 messages: Vec<ErrorMessage>,
88 }
89
90 struct ErrorMessage {
91 // Span is implemented as an index into a thread-local interner to keep the
92 // size small. It is not safe to access from a different thread. We want
93 // errors to be Send and Sync to play nicely with the Failure crate, so pin
94 // the span we're given to its original thread and assume it is
95 // Span::call_site if accessed from any other thread.
96 start_span: ThreadBound<Span>,
97 end_span: ThreadBound<Span>,
98 message: String,
99 }
100
101 #[cfg(test)]
102 struct _Test
103 where
104 Error: Send + Sync;
105
106 impl Error {
107 /// Usually the [`ParseStream::error`] method will be used instead, which
108 /// automatically uses the correct span from the current position of the
109 /// parse stream.
110 ///
111 /// Use `Error::new` when the error needs to be triggered on some span other
112 /// than where the parse stream is currently positioned.
113 ///
114 /// [`ParseStream::error`]: crate::parse::ParseBuffer::error
115 ///
116 /// # Example
117 ///
118 /// ```
119 /// use syn::{Error, Ident, LitStr, Result, Token};
120 /// use syn::parse::ParseStream;
121 ///
122 /// // Parses input that looks like `name = "string"` where the key must be
123 /// // the identifier `name` and the value may be any string literal.
124 /// // Returns the string literal.
125 /// fn parse_name(input: ParseStream) -> Result<LitStr> {
126 /// let name_token: Ident = input.parse()?;
127 /// if name_token != "name" {
128 /// // Trigger an error not on the current position of the stream,
129 /// // but on the position of the unexpected identifier.
130 /// return Err(Error::new(name_token.span(), "expected `name`"));
131 /// }
132 /// input.parse::<Token![=]>()?;
133 /// let s: LitStr = input.parse()?;
134 /// Ok(s)
135 /// }
136 /// ```
new<T: Display>(span: Span, message: T) -> Self137 pub fn new<T: Display>(span: Span, message: T) -> Self {
138 Error {
139 messages: vec![ErrorMessage {
140 start_span: ThreadBound::new(span),
141 end_span: ThreadBound::new(span),
142 message: message.to_string(),
143 }],
144 }
145 }
146
147 /// Creates an error with the specified message spanning the given syntax
148 /// tree node.
149 ///
150 /// Unlike the `Error::new` constructor, this constructor takes an argument
151 /// `tokens` which is a syntax tree node. This allows the resulting `Error`
152 /// to attempt to span all tokens inside of `tokens`. While you would
153 /// typically be able to use the `Spanned` trait with the above `Error::new`
154 /// constructor, implementation limitations today mean that
155 /// `Error::new_spanned` may provide a higher-quality error message on
156 /// stable Rust.
157 ///
158 /// When in doubt it's recommended to stick to `Error::new` (or
159 /// `ParseStream::error`)!
160 #[cfg(feature = "printing")]
new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self161 pub fn new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self {
162 let mut iter = tokens.into_token_stream().into_iter();
163 let start = iter.next().map_or_else(Span::call_site, |t| t.span());
164 let end = iter.last().map_or(start, |t| t.span());
165 Error {
166 messages: vec![ErrorMessage {
167 start_span: ThreadBound::new(start),
168 end_span: ThreadBound::new(end),
169 message: message.to_string(),
170 }],
171 }
172 }
173
174 /// The source location of the error.
175 ///
176 /// Spans are not thread-safe so this function returns `Span::call_site()`
177 /// if called from a different thread than the one on which the `Error` was
178 /// originally created.
span(&self) -> Span179 pub fn span(&self) -> Span {
180 let start = match self.messages[0].start_span.get() {
181 Some(span) => *span,
182 None => return Span::call_site(),
183 };
184 let end = match self.messages[0].end_span.get() {
185 Some(span) => *span,
186 None => return Span::call_site(),
187 };
188 start.join(end).unwrap_or(start)
189 }
190
191 /// Render the error as an invocation of [`compile_error!`].
192 ///
193 /// The [`parse_macro_input!`] macro provides a convenient way to invoke
194 /// this method correctly in a procedural macro.
195 ///
196 /// [`compile_error!`]: https://doc.rust-lang.org/std/macro.compile_error.html
to_compile_error(&self) -> TokenStream197 pub fn to_compile_error(&self) -> TokenStream {
198 self.messages
199 .iter()
200 .map(ErrorMessage::to_compile_error)
201 .collect()
202 }
203
204 /// Add another error message to self such that when `to_compile_error()` is
205 /// called, both errors will be emitted together.
combine(&mut self, another: Error)206 pub fn combine(&mut self, another: Error) {
207 self.messages.extend(another.messages)
208 }
209 }
210
211 impl ErrorMessage {
to_compile_error(&self) -> TokenStream212 fn to_compile_error(&self) -> TokenStream {
213 let start = self
214 .start_span
215 .get()
216 .cloned()
217 .unwrap_or_else(Span::call_site);
218 let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site);
219
220 // compile_error!($message)
221 TokenStream::from_iter(vec![
222 TokenTree::Ident(Ident::new("compile_error", start)),
223 TokenTree::Punct({
224 let mut punct = Punct::new('!', Spacing::Alone);
225 punct.set_span(start);
226 punct
227 }),
228 TokenTree::Group({
229 let mut group = Group::new(Delimiter::Brace, {
230 TokenStream::from_iter(vec![TokenTree::Literal({
231 let mut string = Literal::string(&self.message);
232 string.set_span(end);
233 string
234 })])
235 });
236 group.set_span(end);
237 group
238 }),
239 ])
240 }
241 }
242
243 #[cfg(feature = "parsing")]
new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error244 pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
245 if cursor.eof() {
246 Error::new(scope, format!("unexpected end of input, {}", message))
247 } else {
248 let span = crate::buffer::open_span_of_group(cursor);
249 Error::new(span, message)
250 }
251 }
252
253 impl Debug for Error {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result254 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
255 if self.messages.len() == 1 {
256 formatter
257 .debug_tuple("Error")
258 .field(&self.messages[0])
259 .finish()
260 } else {
261 formatter
262 .debug_tuple("Error")
263 .field(&self.messages)
264 .finish()
265 }
266 }
267 }
268
269 impl Debug for ErrorMessage {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result270 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
271 Debug::fmt(&self.message, formatter)
272 }
273 }
274
275 impl Display for Error {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result276 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
277 formatter.write_str(&self.messages[0].message)
278 }
279 }
280
281 impl Clone for ErrorMessage {
clone(&self) -> Self282 fn clone(&self) -> Self {
283 let start = self
284 .start_span
285 .get()
286 .cloned()
287 .unwrap_or_else(Span::call_site);
288 let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site);
289 ErrorMessage {
290 start_span: ThreadBound::new(start),
291 end_span: ThreadBound::new(end),
292 message: self.message.clone(),
293 }
294 }
295 }
296
297 impl std::error::Error for Error {
description(&self) -> &str298 fn description(&self) -> &str {
299 "parse error"
300 }
301 }
302
303 impl From<LexError> for Error {
from(err: LexError) -> Self304 fn from(err: LexError) -> Self {
305 Error::new(Span::call_site(), format!("{:?}", err))
306 }
307 }
308
309 impl IntoIterator for Error {
310 type Item = Error;
311 type IntoIter = IntoIter;
312
into_iter(self) -> Self::IntoIter313 fn into_iter(self) -> Self::IntoIter {
314 IntoIter {
315 messages: self.messages.into_iter(),
316 }
317 }
318 }
319
320 pub struct IntoIter {
321 messages: vec::IntoIter<ErrorMessage>,
322 }
323
324 impl Iterator for IntoIter {
325 type Item = Error;
326
next(&mut self) -> Option<Self::Item>327 fn next(&mut self) -> Option<Self::Item> {
328 Some(Error {
329 messages: vec![self.messages.next()?],
330 })
331 }
332 }
333
334 impl<'a> IntoIterator for &'a Error {
335 type Item = Error;
336 type IntoIter = Iter<'a>;
337
into_iter(self) -> Self::IntoIter338 fn into_iter(self) -> Self::IntoIter {
339 Iter {
340 messages: self.messages.iter(),
341 }
342 }
343 }
344
345 pub struct Iter<'a> {
346 messages: slice::Iter<'a, ErrorMessage>,
347 }
348
349 impl<'a> Iterator for Iter<'a> {
350 type Item = Error;
351
next(&mut self) -> Option<Self::Item>352 fn next(&mut self) -> Option<Self::Item> {
353 Some(Error {
354 messages: vec![self.messages.next()?.clone()],
355 })
356 }
357 }
358