]>
git.proxmox.com Git - rustc.git/blob - vendor/syn/src/error.rs
1 #[cfg(feature = "parsing")]
2 use crate::buffer
::Cursor
;
3 use crate::thread
::ThreadBound
;
5 Delimiter
, Group
, Ident
, LexError
, Literal
, Punct
, Spacing
, Span
, TokenStream
, TokenTree
,
7 #[cfg(feature = "printing")]
9 use std
::fmt
::{self, Debug, Display}
;
10 use std
::iter
::FromIterator
;
14 /// The result of a Syn parser.
15 pub type Result
<T
> = std
::result
::Result
<T
, Error
>;
17 /// Error returned when a Syn parser cannot parse the input tokens.
19 /// # Error reporting in proc macros
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.
26 /// [`compile_error!`]: std::compile_error!
28 /// When parsing macro input, the [`parse_macro_input!`] macro handles the
29 /// conversion to `compile_error!` automatically.
31 /// [`parse_macro_input!`]: crate::parse_macro_input!
34 /// # extern crate proc_macro;
36 /// use proc_macro::TokenStream;
37 /// use syn::{parse_macro_input, AttributeArgs, ItemFn};
39 /// # const IGNORE: &str = stringify! {
40 /// #[proc_macro_attribute]
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);
47 /// # TokenStream::new()
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!`.
55 /// [`.to_compile_error()`]: Error::to_compile_error
56 /// [`.into_compile_error()`]: Error::into_compile_error
59 /// # extern crate proc_macro;
61 /// # use proc_macro::TokenStream;
62 /// # use syn::{parse_macro_input, DeriveInput};
64 /// # const IGNORE: &str = stringify! {
65 /// #[proc_macro_derive(MyDerive)]
67 /// pub fn my_derive(input: TokenStream) -> TokenStream {
68 /// let input = parse_macro_input!(input as DeriveInput);
70 /// // fn(DeriveInput) -> syn::Result<proc_macro2::TokenStream>
71 /// expand::my_derive(input)
72 /// .unwrap_or_else(syn::Error::into_compile_error)
77 /// # use proc_macro2::TokenStream;
78 /// # use syn::{DeriveInput, Result};
80 /// # pub fn my_derive(input: DeriveInput) -> Result<TokenStream> {
81 /// # unimplemented!()
86 messages
: Vec
<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
>,
106 /// Usually the [`ParseStream::error`] method will be used instead, which
107 /// automatically uses the correct span from the current position of the
110 /// Use `Error::new` when the error needs to be triggered on some span other
111 /// than where the parse stream is currently positioned.
113 /// [`ParseStream::error`]: crate::parse::ParseBuffer::error
118 /// use syn::{Error, Ident, LitStr, Result, Token};
119 /// use syn::parse::ParseStream;
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`"));
131 /// input.parse::<Token![=]>()?;
132 /// let s: LitStr = input.parse()?;
136 pub fn new
<T
: Display
>(span
: Span
, message
: T
) -> Self {
138 messages
: vec
![ErrorMessage
{
139 start_span
: ThreadBound
::new(span
),
140 end_span
: ThreadBound
::new(span
),
141 message
: message
.to_string(),
146 /// Creates an error with the specified message spanning the given syntax
149 /// Unlike the `Error::new` constructor, this constructor takes an argument
150 /// `tokens` which is a syntax tree node. This allows the resulting `Error`
151 /// to attempt to span all tokens inside of `tokens`. While you would
152 /// typically be able to use the `Spanned` trait with the above `Error::new`
153 /// constructor, implementation limitations today mean that
154 /// `Error::new_spanned` may provide a higher-quality error message on
157 /// When in doubt it's recommended to stick to `Error::new` (or
158 /// `ParseStream::error`)!
159 #[cfg(feature = "printing")]
160 pub fn new_spanned
<T
: ToTokens
, U
: Display
>(tokens
: T
, message
: U
) -> Self {
161 let mut iter
= tokens
.into_token_stream().into_iter();
162 let start
= iter
.next().map_or_else(Span
::call_site
, |t
| t
.span());
163 let end
= iter
.last().map_or(start
, |t
| t
.span());
165 messages
: vec
![ErrorMessage
{
166 start_span
: ThreadBound
::new(start
),
167 end_span
: ThreadBound
::new(end
),
168 message
: message
.to_string(),
173 /// The source location of the error.
175 /// Spans are not thread-safe so this function returns `Span::call_site()`
176 /// if called from a different thread than the one on which the `Error` was
177 /// originally created.
178 pub fn span(&self) -> Span
{
179 let start
= match self.messages
[0].start_span
.get() {
181 None
=> return Span
::call_site(),
183 let end
= match self.messages
[0].end_span
.get() {
185 None
=> return Span
::call_site(),
187 start
.join(end
).unwrap_or(start
)
190 /// Render the error as an invocation of [`compile_error!`].
192 /// The [`parse_macro_input!`] macro provides a convenient way to invoke
193 /// this method correctly in a procedural macro.
195 /// [`compile_error!`]: std::compile_error!
196 /// [`parse_macro_input!`]: crate::parse_macro_input!
197 pub fn to_compile_error(&self) -> TokenStream
{
200 .map(ErrorMessage
::to_compile_error
)
204 /// Render the error as an invocation of [`compile_error!`].
206 /// [`compile_error!`]: std::compile_error!
211 /// # extern crate proc_macro;
213 /// use proc_macro::TokenStream;
214 /// use syn::{parse_macro_input, DeriveInput, Error};
216 /// # const _: &str = stringify! {
217 /// #[proc_macro_derive(MyTrait)]
219 /// pub fn derive_my_trait(input: TokenStream) -> TokenStream {
220 /// let input = parse_macro_input!(input as DeriveInput);
221 /// my_trait::expand(input)
222 /// .unwrap_or_else(Error::into_compile_error)
227 /// use proc_macro2::TokenStream;
228 /// use syn::{DeriveInput, Result};
230 /// pub(crate) fn expand(input: DeriveInput) -> Result<TokenStream> {
232 /// # unimplemented!()
236 pub fn into_compile_error(self) -> TokenStream
{
237 self.to_compile_error()
240 /// Add another error message to self such that when `to_compile_error()` is
241 /// called, both errors will be emitted together.
242 pub fn combine(&mut self, another
: Error
) {
243 self.messages
.extend(another
.messages
);
248 fn to_compile_error(&self) -> TokenStream
{
253 .unwrap_or_else(Span
::call_site
);
254 let end
= self.end_span
.get().cloned().unwrap_or_else(Span
::call_site
);
256 // compile_error!($message)
257 TokenStream
::from_iter(vec
![
258 TokenTree
::Ident(Ident
::new("compile_error", start
)),
260 let mut punct
= Punct
::new('
!'
, Spacing
::Alone
);
261 punct
.set_span(start
);
265 let mut group
= Group
::new(Delimiter
::Brace
, {
266 TokenStream
::from_iter(vec
![TokenTree
::Literal({
267 let mut string
= Literal
::string(&self.message
);
268 string
.set_span(end
);
279 #[cfg(feature = "parsing")]
280 pub fn new_at
<T
: Display
>(scope
: Span
, cursor
: Cursor
, message
: T
) -> Error
{
282 Error
::new(scope
, format
!("unexpected end of input, {}", message
))
284 let span
= crate::buffer
::open_span_of_group(cursor
);
285 Error
::new(span
, message
)
289 #[cfg(all(feature = "parsing", any(feature = "full", feature = "derive")))]
290 pub fn new2
<T
: Display
>(start
: Span
, end
: Span
, message
: T
) -> Error
{
292 messages
: vec
![ErrorMessage
{
293 start_span
: ThreadBound
::new(start
),
294 end_span
: ThreadBound
::new(end
),
295 message
: message
.to_string(),
300 impl Debug
for Error
{
301 fn fmt(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
302 if self.messages
.len() == 1 {
304 .debug_tuple("Error")
305 .field(&self.messages
[0])
309 .debug_tuple("Error")
310 .field(&self.messages
)
316 impl Debug
for ErrorMessage
{
317 fn fmt(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
318 Debug
::fmt(&self.message
, formatter
)
322 impl Display
for Error
{
323 fn fmt(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
324 formatter
.write_str(&self.messages
[0].message
)
328 impl Clone
for Error
{
329 fn clone(&self) -> Self {
331 messages
: self.messages
.clone(),
336 impl Clone
for ErrorMessage
{
337 fn clone(&self) -> Self {
342 .unwrap_or_else(Span
::call_site
);
343 let end
= self.end_span
.get().cloned().unwrap_or_else(Span
::call_site
);
345 start_span
: ThreadBound
::new(start
),
346 end_span
: ThreadBound
::new(end
),
347 message
: self.message
.clone(),
352 impl std
::error
::Error
for Error {}
354 impl From
<LexError
> for Error
{
355 fn from(err
: LexError
) -> Self {
356 Error
::new(err
.span(), "lex error")
360 impl IntoIterator
for Error
{
362 type IntoIter
= IntoIter
;
364 fn into_iter(self) -> Self::IntoIter
{
366 messages
: self.messages
.into_iter(),
371 pub struct IntoIter
{
372 messages
: vec
::IntoIter
<ErrorMessage
>,
375 impl Iterator
for IntoIter
{
378 fn next(&mut self) -> Option
<Self::Item
> {
380 messages
: vec
![self.messages
.next()?
],
385 impl<'a
> IntoIterator
for &'a Error
{
387 type IntoIter
= Iter
<'a
>;
389 fn into_iter(self) -> Self::IntoIter
{
391 messages
: self.messages
.iter(),
396 pub struct Iter
<'a
> {
397 messages
: slice
::Iter
<'a
, ErrorMessage
>,
400 impl<'a
> Iterator
for Iter
<'a
> {
403 fn next(&mut self) -> Option
<Self::Item
> {
405 messages
: vec
![self.messages
.next()?
.clone()],
410 impl Extend
<Error
> for Error
{
411 fn extend
<T
: IntoIterator
<Item
= Error
>>(&mut self, iter
: T
) {