syn/error.rs
1use std;
2use std::fmt::{self, Debug, Display};
3use std::iter::FromIterator;
4use std::slice;
5use std::vec;
6
7use proc_macro2::{
8 Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
9};
10#[cfg(feature = "printing")]
11use quote::ToTokens;
12
13#[cfg(feature = "parsing")]
14use crate::buffer::Cursor;
15use crate::thread::ThreadBound;
16
17/// The result of a Syn parser.
18pub 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)]
86pub struct Error {
87 messages: Vec<ErrorMessage>,
88}
89
90struct 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)]
102struct _Test
103where
104 Error: Send + Sync;
105
106impl 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 /// ```
137 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")]
161 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.
179 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
197 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.
206 pub fn combine(&mut self, another: Error) {
207 self.messages.extend(another.messages)
208 }
209}
210
211impl ErrorMessage {
212 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")]
244pub 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
253impl Debug for Error {
254 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
269impl Debug for ErrorMessage {
270 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
271 Debug::fmt(&self.message, formatter)
272 }
273}
274
275impl Display for Error {
276 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
277 formatter.write_str(&self.messages[0].message)
278 }
279}
280
281impl Clone for ErrorMessage {
282 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
297impl std::error::Error for Error {
298 fn description(&self) -> &str {
299 "parse error"
300 }
301}
302
303impl From<LexError> for Error {
304 fn from(err: LexError) -> Self {
305 Error::new(Span::call_site(), format!("{:?}", err))
306 }
307}
308
309impl IntoIterator for Error {
310 type Item = Error;
311 type IntoIter = IntoIter;
312
313 fn into_iter(self) -> Self::IntoIter {
314 IntoIter {
315 messages: self.messages.into_iter(),
316 }
317 }
318}
319
320pub struct IntoIter {
321 messages: vec::IntoIter<ErrorMessage>,
322}
323
324impl Iterator for IntoIter {
325 type Item = Error;
326
327 fn next(&mut self) -> Option<Self::Item> {
328 Some(Error {
329 messages: vec![self.messages.next()?],
330 })
331 }
332}
333
334impl<'a> IntoIterator for &'a Error {
335 type Item = Error;
336 type IntoIter = Iter<'a>;
337
338 fn into_iter(self) -> Self::IntoIter {
339 Iter {
340 messages: self.messages.iter(),
341 }
342 }
343}
344
345pub struct Iter<'a> {
346 messages: slice::Iter<'a, ErrorMessage>,
347}
348
349impl<'a> Iterator for Iter<'a> {
350 type Item = Error;
351
352 fn next(&mut self) -> Option<Self::Item> {
353 Some(Error {
354 messages: vec![self.messages.next()?.clone()],
355 })
356 }
357}