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 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 189 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. 210 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! 225 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 /// ``` 264 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. 270 pub fn combine(&mut self, another: Error) { 271 self.messages.extend(another.messages); 272 } 273} 274 275impl ErrorMessage { 276 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")] 327pub(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")))] 337pub(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 350impl Debug for Error { 351 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 366impl Debug for ErrorMessage { 367 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 368 Debug::fmt(&self.message, formatter) 369 } 370} 371 372impl Display for Error { 373 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 374 formatter.write_str(&self.messages[0].message) 375 } 376} 377 378impl Clone for Error { 379 fn clone(&self) -> Self { 380 Error { 381 messages: self.messages.clone(), 382 } 383 } 384} 385 386impl Clone for ErrorMessage { 387 fn clone(&self) -> Self { 388 ErrorMessage { 389 span: self.span, 390 message: self.message.clone(), 391 } 392 } 393} 394 395impl Clone for SpanRange { 396 fn clone(&self) -> Self { 397 *self 398 } 399} 400 401impl Copy for SpanRange {} 402 403impl std::error::Error for Error {} 404 405impl From<LexError> for Error { 406 fn from(err: LexError) -> Self { 407 Error::new(err.span(), err) 408 } 409} 410 411impl IntoIterator for Error { 412 type Item = Error; 413 type IntoIter = IntoIter; 414 415 fn into_iter(self) -> Self::IntoIter { 416 IntoIter { 417 messages: self.messages.into_iter(), 418 } 419 } 420} 421 422pub struct IntoIter { 423 messages: vec::IntoIter<ErrorMessage>, 424} 425 426impl Iterator for IntoIter { 427 type Item = Error; 428 429 fn next(&mut self) -> Option<Self::Item> { 430 Some(Error { 431 messages: vec![self.messages.next()?], 432 }) 433 } 434} 435 436impl<'a> IntoIterator for &'a Error { 437 type Item = Error; 438 type IntoIter = Iter<'a>; 439 440 fn into_iter(self) -> Self::IntoIter { 441 Iter { 442 messages: self.messages.iter(), 443 } 444 } 445} 446 447pub struct Iter<'a> { 448 messages: slice::Iter<'a, ErrorMessage>, 449} 450 451impl<'a> Iterator for Iter<'a> { 452 type Item = Error; 453 454 fn next(&mut self) -> Option<Self::Item> { 455 Some(Error { 456 messages: vec![self.messages.next()?.clone()], 457 }) 458 } 459} 460 461impl Extend<Error> for Error { 462 fn extend<T: IntoIterator<Item = Error>>(&mut self, iter: T) { 463 for err in iter { 464 self.combine(err); 465 } 466 } 467} 468